Make __builtin_cpu_{init|supports|is} target independent and provide an
opt-in query for targets that want to support it. Each target is still
responsible for their specific lowering/code-gen. Also provide code-gen
for PowerPC.
I originally proposed this in https://reviews.llvm.org/D152914 and this
addresses the comments I received there.
---------
Co-authored-by: Nemanja Ivanovic <nemanjaivanovic@nemanjas-air.kpn>
Co-authored-by: Nemanja Ivanovic <nemanja@synopsys.com>
162 lines
7.1 KiB
C
162 lines
7.1 KiB
C
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 3
|
|
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm -o - %s | \
|
|
// RUN: FileCheck %s --check-prefix=CHECK-X86
|
|
// RUN: %clang_cc1 -triple ppc64le-linux-gnu -emit-llvm -o - %s | FileCheck %s \
|
|
// RUN: --check-prefix=CHECK-PPC
|
|
|
|
#ifndef __PPC__
|
|
|
|
// Test that we have the structure definition, the gep offsets, the name of the
|
|
// global, the bit grab, and the icmp correct.
|
|
extern void a(const char *);
|
|
|
|
|
|
// CHECK-X86-LABEL: define dso_local i32 @main(
|
|
// CHECK-X86-SAME: ) #[[ATTR0:[0-9]+]] {
|
|
// CHECK-X86-NEXT: entry:
|
|
// CHECK-X86-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
|
// CHECK-X86-NEXT: store i32 0, ptr [[RETVAL]], align 4
|
|
// CHECK-X86-NEXT: call void @__cpu_indicator_init()
|
|
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ({ i32, i32, i32, [1 x i32] }, ptr @__cpu_model, i32 0, i32 3, i32 0), align 4
|
|
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 256
|
|
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 256
|
|
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
|
// CHECK-X86-NEXT: br i1 [[TMP3]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-X86: if.then:
|
|
// CHECK-X86-NEXT: call void @a(ptr noundef @.str)
|
|
// CHECK-X86-NEXT: br label [[IF_END]]
|
|
// CHECK-X86: if.end:
|
|
// CHECK-X86-NEXT: [[TMP4:%.*]] = load i32, ptr @__cpu_features2, align 4
|
|
// CHECK-X86-NEXT: [[TMP5:%.*]] = and i32 [[TMP4]], 1
|
|
// CHECK-X86-NEXT: [[TMP6:%.*]] = icmp eq i32 [[TMP5]], 1
|
|
// CHECK-X86-NEXT: [[TMP7:%.*]] = and i1 true, [[TMP6]]
|
|
// CHECK-X86-NEXT: br i1 [[TMP7]], label [[IF_THEN1:%.*]], label [[IF_END2:%.*]]
|
|
// CHECK-X86: if.then1:
|
|
// CHECK-X86-NEXT: call void @a(ptr noundef @.str.1)
|
|
// CHECK-X86-NEXT: br label [[IF_END2]]
|
|
// CHECK-X86: if.end2:
|
|
// CHECK-X86-NEXT: ret i32 0
|
|
//
|
|
int main(void) {
|
|
__builtin_cpu_init();
|
|
|
|
// CHECK: call void @__cpu_indicator_init
|
|
|
|
if (__builtin_cpu_supports("sse4.2"))
|
|
a("sse4.2");
|
|
|
|
|
|
if (__builtin_cpu_supports("gfni"))
|
|
a("gfni");
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
// CHECK-X86-LABEL: define dso_local i32 @baseline(
|
|
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
|
// CHECK-X86-NEXT: entry:
|
|
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 1), align 4
|
|
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], -2147483648
|
|
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], -2147483648
|
|
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
|
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
|
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
|
//
|
|
int baseline() { return __builtin_cpu_supports("x86-64"); }
|
|
|
|
// CHECK-X86-LABEL: define dso_local i32 @v2(
|
|
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
|
// CHECK-X86-NEXT: entry:
|
|
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
|
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 1
|
|
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 1
|
|
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
|
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
|
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
|
//
|
|
int v2() { return __builtin_cpu_supports("x86-64-v2"); }
|
|
|
|
// CHECK-X86-LABEL: define dso_local i32 @v3(
|
|
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
|
// CHECK-X86-NEXT: entry:
|
|
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
|
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 2
|
|
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 2
|
|
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
|
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
|
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
|
//
|
|
int v3() { return __builtin_cpu_supports("x86-64-v3"); }
|
|
|
|
// CHECK-X86-LABEL: define dso_local i32 @v4(
|
|
// CHECK-X86-SAME: ) #[[ATTR0]] {
|
|
// CHECK-X86-NEXT: entry:
|
|
// CHECK-X86-NEXT: [[TMP0:%.*]] = load i32, ptr getelementptr inbounds ([3 x i32], ptr @__cpu_features2, i32 0, i32 2), align 4
|
|
// CHECK-X86-NEXT: [[TMP1:%.*]] = and i32 [[TMP0]], 4
|
|
// CHECK-X86-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 4
|
|
// CHECK-X86-NEXT: [[TMP3:%.*]] = and i1 true, [[TMP2]]
|
|
// CHECK-X86-NEXT: [[CONV:%.*]] = zext i1 [[TMP3]] to i32
|
|
// CHECK-X86-NEXT: ret i32 [[CONV]]
|
|
//
|
|
int v4() { return __builtin_cpu_supports("x86-64-v4"); }
|
|
#else
|
|
// CHECK-PPC-LABEL: define dso_local signext i32 @test(
|
|
// CHECK-PPC-SAME: i32 noundef signext [[A:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
// CHECK-PPC-NEXT: entry:
|
|
// CHECK-PPC-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
|
// CHECK-PPC-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-PPC-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: [[CPU_SUPPORTS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 2)
|
|
// CHECK-PPC-NEXT: [[TMP0:%.*]] = and i32 [[CPU_SUPPORTS]], 8388608
|
|
// CHECK-PPC-NEXT: [[TMP1:%.*]] = icmp ne i32 [[TMP0]], 0
|
|
// CHECK-PPC-NEXT: br i1 [[TMP1]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
|
|
// CHECK-PPC: if.then:
|
|
// CHECK-PPC-NEXT: [[TMP2:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: store i32 [[TMP2]], ptr [[RETVAL]], align 4
|
|
// CHECK-PPC-NEXT: br label [[RETURN:%.*]]
|
|
// CHECK-PPC: if.else:
|
|
// CHECK-PPC-NEXT: [[CPU_SUPPORTS1:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 1)
|
|
// CHECK-PPC-NEXT: [[TMP3:%.*]] = and i32 [[CPU_SUPPORTS1]], 67108864
|
|
// CHECK-PPC-NEXT: [[TMP4:%.*]] = icmp ne i32 [[TMP3]], 0
|
|
// CHECK-PPC-NEXT: br i1 [[TMP4]], label [[IF_THEN2:%.*]], label [[IF_ELSE3:%.*]]
|
|
// CHECK-PPC: if.then2:
|
|
// CHECK-PPC-NEXT: [[TMP5:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 5
|
|
// CHECK-PPC-NEXT: store i32 [[SUB]], ptr [[RETVAL]], align 4
|
|
// CHECK-PPC-NEXT: br label [[RETURN]]
|
|
// CHECK-PPC: if.else3:
|
|
// CHECK-PPC-NEXT: [[CPU_IS:%.*]] = call i32 @llvm.ppc.fixed.addr.ld(i32 3)
|
|
// CHECK-PPC-NEXT: [[TMP6:%.*]] = icmp eq i32 [[CPU_IS]], 39
|
|
// CHECK-PPC-NEXT: br i1 [[TMP6]], label [[IF_THEN4:%.*]], label [[IF_END:%.*]]
|
|
// CHECK-PPC: if.then4:
|
|
// CHECK-PPC-NEXT: [[TMP7:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: [[TMP8:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP7]], [[TMP8]]
|
|
// CHECK-PPC-NEXT: store i32 [[ADD]], ptr [[RETVAL]], align 4
|
|
// CHECK-PPC-NEXT: br label [[RETURN]]
|
|
// CHECK-PPC: if.end:
|
|
// CHECK-PPC-NEXT: br label [[IF_END5:%.*]]
|
|
// CHECK-PPC: if.end5:
|
|
// CHECK-PPC-NEXT: br label [[IF_END6:%.*]]
|
|
// CHECK-PPC: if.end6:
|
|
// CHECK-PPC-NEXT: [[TMP9:%.*]] = load i32, ptr [[A_ADDR]], align 4
|
|
// CHECK-PPC-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP9]], 5
|
|
// CHECK-PPC-NEXT: store i32 [[ADD7]], ptr [[RETVAL]], align 4
|
|
// CHECK-PPC-NEXT: br label [[RETURN]]
|
|
// CHECK-PPC: return:
|
|
// CHECK-PPC-NEXT: [[TMP10:%.*]] = load i32, ptr [[RETVAL]], align 4
|
|
// CHECK-PPC-NEXT: ret i32 [[TMP10]]
|
|
//
|
|
int test(int a) {
|
|
if (__builtin_cpu_supports("arch_3_00")) // HWCAP2
|
|
return a;
|
|
else if (__builtin_cpu_supports("mmu")) // HWCAP
|
|
return a - 5;
|
|
else if (__builtin_cpu_is("power7")) // CPUID
|
|
return a + a;
|
|
return a + 5;
|
|
}
|
|
#endif
|