Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -3922,6 +3922,9 @@ if (!CPUProfile.empty()) Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); + // ACLE predefines. + Builder.defineMacro("__ARM_ACLE", "200"); + // Subtarget options. // FIXME: It's more complicated than this and we don't really support Index: lib/Headers/CMakeLists.txt =================================================================== --- lib/Headers/CMakeLists.txt +++ lib/Headers/CMakeLists.txt @@ -1,6 +1,7 @@ set(files altivec.h ammintrin.h + arm_acle.h avxintrin.h avx2intrin.h bmiintrin.h Index: lib/Headers/arm_acle.h =================================================================== --- /dev/null +++ lib/Headers/arm_acle.h @@ -0,0 +1,138 @@ +/*===---- arm_acle.h - ARM Non-Neon intrinsics -----------------------------=== + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + *===-----------------------------------------------------------------------=== + */ + +#ifndef __ARM_ACLE_H +#define __ARM_ACLE_H + +#ifndef __ARM_ACLE +#error "ACLE intrinsics support not enabled." +#endif + +#include + +/* Miscellaneous data-processing intrinsics */ + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __clz(uint32_t t) { + return __builtin_clz(t); +} + +static __inline__ unsigned long __attribute__((always_inline, nodebug)) + __clzl(unsigned long t) { + return __builtin_clzl(t); +} + +static __inline__ uint64_t __attribute__((always_inline, nodebug)) + __clzll(uint64_t t) { +#if __SIZEOF_LONG_LONG__ == 8 + return __builtin_clzll(t); +#else + return __builtin_clzl(t); +#endif +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __rev(uint32_t t) { + return __builtin_bswap32(t); +} + +static __inline__ unsigned long __attribute__((always_inline, nodebug)) + __revl(unsigned long t) { +#if __SIZEOF_LONG__ == 4 + return __builtin_bswap32(t); +#else + return __builtin_bswap64(t); +#endif +} + +static __inline__ uint64_t __attribute__((always_inline, nodebug)) + __revll(uint64_t t) { + return __builtin_bswap64(t); +} + + +/* + * Saturating intrinsics + * + * FIXME: Change guard to their corrosponding __ARM_FEATURE flag when Q flag + * intrinsics are implemented and the flag is enabled. + */ +#if __ARM_32BIT_STATE +#define __ssat(x, y) __builtin_arm_ssat(x, y) +#define __usat(x, y) __builtin_arm_usat(x, y) + +static __inline__ int32_t __attribute__((always_inline, nodebug)) + __qadd(int32_t t, int32_t v) { + return __builtin_arm_qadd(t, v); +} + +static __inline__ int32_t __attribute__((always_inline, nodebug)) + __qsub(int32_t t, int32_t v) { + return __builtin_arm_qsub(t, v); +} +#endif + +/* CRC32 intrinsics */ +#if __ARM_FEATURE_CRC32 +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32b(uint32_t a, uint8_t b) { + return __builtin_arm_crc32b(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32h(uint32_t a, uint16_t b) { + return __builtin_arm_crc32h(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32w(uint32_t a, uint32_t b) { + return __builtin_arm_crc32w(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32d(uint32_t a, uint64_t b) { + return __builtin_arm_crc32d(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32cb(uint32_t a, uint8_t b) { + return __builtin_arm_crc32cb(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32ch(uint32_t a, uint16_t b) { + return __builtin_arm_crc32ch(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32cw(uint32_t a, uint32_t b) { + return __builtin_arm_crc32cw(a, b); +} + +static __inline__ uint32_t __attribute__((always_inline, nodebug)) + __crc32cd(uint32_t a, uint64_t b) { + return __builtin_arm_crc32cd(a, b); +} +#endif + +#endif /* __ARM_ACLE_H */ Index: test/CodeGen/arm_acle.c =================================================================== --- /dev/null +++ test/CodeGen/arm_acle.c @@ -0,0 +1,129 @@ +// RUN: %clang_cc1 -triple armv8 -target-cpu cortex-a57 -O -S -emit-llvm -o - %s | FileCheck %s -check-prefix=ARM -check-prefix=AArch32 +// RUN: %clang_cc1 -triple aarch64 -target-cpu cortex-a57 -O -S -emit-llvm -o - %s | FileCheck %s -check-prefix=ARM -check-prefix=AArch64 + +#include +#include + +/* Miscellaneous data-processing intrinsics */ +// ARM-LABEL: test_rev +// ARM: call i32 @llvm.bswap.i32(i32 %t) +uint32_t test_rev(uint32_t t) { + return __rev(t); +} + +// ARM-LABEL: test_revl +// AArch32: call i32 @llvm.bswap.i32(i32 %t) +// AArch64: call i64 @llvm.bswap.i64(i64 %t) +long test_revl(long t) { + return __revl(t); +} + +// ARM-LABEL: test_revll +// ARM: call i64 @llvm.bswap.i64(i64 %t) +uint64_t test_revll(uint64_t t) { + return __revll(t); +} + +// ARM-LABEL: test_clz +// ARM: call i32 @llvm.ctlz.i32(i32 %t, i1 false) +uint32_t test_clz(uint32_t t) { + return __clz(t); +} + +// ARM-LABEL: test_clzl +// AArch32: call i32 @llvm.ctlz.i32(i32 %t, i1 false) +// AArch64: call i64 @llvm.ctlz.i64(i64 %t, i1 false) +long test_clzl(long t) { + return __clzl(t); +} + +// ARM-LABEL: test_clzll +// ARM: call i64 @llvm.ctlz.i64(i64 %t, i1 false) +uint64_t test_clzll(uint64_t t) { + return __clzll(t); +} + +/* Saturating intrinsics */ +#ifdef __ARM_32BIT_STATE +// AArch32-LABEL: test_ssat +// AArch32: call i32 @llvm.arm.ssat(i32 %t, i32 1) +int32_t test_ssat(int32_t t) { + return __ssat(t, 1); +} + +// AArch32-LABEL: test_usat +// AArch32: call i32 @llvm.arm.usat(i32 %t, i32 2) +int32_t test_usat(int32_t t) { + return __usat(t, 2); +} +// AArch32-LABEL: test_qadd +// AArch32: call i32 @llvm.arm.qadd(i32 %a, i32 %b) +int32_t test_qadd(int32_t a, int32_t b) { + return __qadd(a, b); +} + +// AArch32-LABEL: test_qsub +// AArch32: call i32 @llvm.arm.qsub(i32 %a, i32 %b) +int32_t test_qsub(int32_t a, int32_t b) { + return __qsub(a, b); +} +#endif + +/* CRC32 intrinsics */ +// ARM-LABEL: test_crc32b +// AArch32: call i32 @llvm.arm.crc32b +// AArch64: call i32 @llvm.aarch64.crc32b +uint32_t test_crc32b(uint32_t a, uint8_t b) { + return __crc32b(a, b); +} + +// ARM-LABEL: test_crc32h +// AArch32: call i32 @llvm.arm.crc32h +// AArch64: call i32 @llvm.aarch64.crc32h +uint32_t test_crc32h(uint32_t a, uint16_t b) { + return __crc32h(a, b); +} + +// ARM-LABEL: test_crc32w +// AArch32: call i32 @llvm.arm.crc32w +// AArch64: call i32 @llvm.aarch64.crc32w +uint32_t test_crc32w(uint32_t a, uint32_t b) { + return __crc32w(a, b); +} + +// ARM-LABEL: test_crc32d +// AArch32: call i32 @llvm.arm.crc32w +// AArch32: call i32 @llvm.arm.crc32w +// AArch64: call i32 @llvm.aarch64.crc32x +uint32_t test_crc32d(uint32_t a, uint64_t b) { + return __crc32d(a, b); +} + +// ARM-LABEL: test_crc32cb +// AArch32: call i32 @llvm.arm.crc32cb +// AArch64: call i32 @llvm.aarch64.crc32cb +uint32_t test_crc32cb(uint32_t a, uint8_t b) { + return __crc32cb(a, b); +} + +// ARM-LABEL: test_crc32ch +// AArch32: call i32 @llvm.arm.crc32ch +// AArch64: call i32 @llvm.aarch64.crc32ch +uint32_t test_crc32ch(uint32_t a, uint16_t b) { + return __crc32ch(a, b); +} + +// ARM-LABEL: test_crc32cw +// AArch32: call i32 @llvm.arm.crc32cw +// AArch64: call i32 @llvm.aarch64.crc32cw +uint32_t test_crc32cw(uint32_t a, uint32_t b) { + return __crc32cw(a, b); +} + +// ARM-LABEL: test_crc32cd +// AArch32: call i32 @llvm.arm.crc32cw +// AArch32: call i32 @llvm.arm.crc32cw +// AArch64: call i32 @llvm.aarch64.crc32cx +uint32_t test_crc32cd(uint32_t a, uint64_t b) { + return __crc32cd(a, b); +} Index: test/Headers/arm-acle-header.c =================================================================== --- /dev/null +++ test/Headers/arm-acle-header.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -triple armv7 -target-cpu cortex-a15 -fsyntax-only -ffreestanding %s +// RUN: %clang_cc1 -triple aarch64 -target-cpu cortex-a53 -fsyntax-only -ffreestanding %s +// RUN: %clang_cc1 -x c++ -triple armv7 -target-cpu cortex-a15 -fsyntax-only -ffreestanding %s +// RUN: %clang_cc1 -x c++ -triple aarch64 -target-cpu cortex-a57 -fsyntax-only -ffreestanding %s +// expected-no-diagnostics + +#include Index: test/Sema/arm_acle.c =================================================================== --- /dev/null +++ test/Sema/arm_acle.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple armv8 -target-cpu cortex-a57 -fsyntax-only -verify %s + +#include + +/* + * Saturating intrinsics + * Second argument for SSAT and USAT intrinsics must be compile-time constant, + * otherwise an error should be raised. + */ +int32_t test_ssat_const_diag(int32_t t, const int32_t v) { + return __ssat(t, v); // expected-error-re {{argument to {{.*}} must be a constant integer}} +} + +int32_t test_usat_const_diag(int32_t t, const int32_t v) { + return __usat(t, v); // expected-error-re {{argument to {{.*}} must be a constant integer}} +}