Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce arm_acle.h supporting existing LLVM builtin intrinsics
Summary: This patch introduces ACLE header file, implementing extensions that can be directly mapped to existing Clang intrinsics. It implements for both AArch32 and AArch64. Reviewers: t.p.northover, compnerd, rengolin Reviewed By: compnerd, rengolin Subscribers: rnk, echristo, compnerd, aemerson, mroth, cfe-commits Differential Revision: http://reviews.llvm.org/D4296 llvm-svn: 211962
- Loading branch information
Showing
6 changed files
with
294 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
set(files | ||
altivec.h | ||
ammintrin.h | ||
arm_acle.h | ||
avxintrin.h | ||
avx2intrin.h | ||
bmiintrin.h | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <stdint.h> | ||
|
||
/* 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 */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <arm_acle.h> | ||
#include <stdint.h> | ||
|
||
/* 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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <arm_acle.h> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// RUN: %clang_cc1 -triple armv8 -target-cpu cortex-a57 -fsyntax-only -verify %s | ||
|
||
#include <arm_acle.h> | ||
|
||
/* | ||
* 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}} | ||
} |