Skip to content

Commit

Permalink
Introduce arm_acle.h supporting existing LLVM builtin intrinsics
Browse files Browse the repository at this point in the history
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
kongy committed Jun 27, 2014
1 parent 4a26c0c commit a44c4d7
Show file tree
Hide file tree
Showing 6 changed files with 294 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clang/lib/Basic/Targets.cpp
Expand Up @@ -3922,6 +3922,9 @@ class ARMTargetInfo : public TargetInfo {
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
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
@@ -1,6 +1,7 @@
set(files
altivec.h
ammintrin.h
arm_acle.h
avxintrin.h
avx2intrin.h
bmiintrin.h
Expand Down
138 changes: 138 additions & 0 deletions clang/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 <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 */
129 changes: 129 additions & 0 deletions clang/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 <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);
}
7 changes: 7 additions & 0 deletions clang/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 <arm_acle.h>
16 changes: 16 additions & 0 deletions clang/test/Sema/arm_acle.c
@@ -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}}
}

0 comments on commit a44c4d7

Please sign in to comment.