[clang] 600d123 - [ARM][CMSE] Add CMSE header and builtins
Momchil Velikov via cfe-commits
cfe-commits at lists.llvm.org
Thu Dec 12 07:01:24 PST 2019
Author: Momchil Velikov
Date: 2019-12-12T15:01:14Z
New Revision: 600d123c6ff16180a20ebb9b55476257bf69513a
URL: https://github.com/llvm/llvm-project/commit/600d123c6ff16180a20ebb9b55476257bf69513a
DIFF: https://github.com/llvm/llvm-project/commit/600d123c6ff16180a20ebb9b55476257bf69513a.diff
LOG: [ARM][CMSE] Add CMSE header and builtins
This is patch C2 as mentioned in RFC
http://lists.llvm.org/pipermail/cfe-dev/2019-March/061834.html
This adds CMSE builtin functions, and introduces arm_cmse.h header which has
useful macros, functions, and data types for end-users of CMSE.
Patch by Javed Absar.
Diferential Revision: https://reviews.llvm.org/D70817
Added:
clang/lib/Headers/arm_cmse.h
clang/test/CodeGen/arm-cmse-nonsecure.c
clang/test/CodeGen/arm-cmse-secure.c
clang/test/CodeGen/arm-cmse.c
clang/test/Headers/arm-cmse-header-ns.c
clang/test/Headers/arm-cmse-header.c
Modified:
clang/include/clang/Basic/BuiltinsARM.def
clang/lib/Headers/CMakeLists.txt
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/BuiltinsARM.def b/clang/include/clang/Basic/BuiltinsARM.def
index 81991a57e2bd..848abb44ad36 100644
--- a/clang/include/clang/Basic/BuiltinsARM.def
+++ b/clang/include/clang/Basic/BuiltinsARM.def
@@ -166,6 +166,12 @@ BUILTIN(__builtin_arm_crc32cw, "UiUiUi", "nc")
BUILTIN(__builtin_arm_crc32d, "UiUiLLUi", "nc")
BUILTIN(__builtin_arm_crc32cd, "UiUiLLUi", "nc")
+// ARMv8-M Security Extensions a.k.a CMSE
+BUILTIN(__builtin_arm_cmse_TT, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTT, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTA, "Uiv*", "n")
+BUILTIN(__builtin_arm_cmse_TTAT, "Uiv*", "n")
+
// HINT
BUILTIN(__builtin_arm_nop, "v", "")
BUILTIN(__builtin_arm_yield, "v", "")
diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt
index 8ff648fdb4e0..85c3124234ad 100644
--- a/clang/lib/Headers/CMakeLists.txt
+++ b/clang/lib/Headers/CMakeLists.txt
@@ -3,6 +3,7 @@ set(files
altivec.h
ammintrin.h
arm_acle.h
+ arm_cmse.h
armintr.h
arm64intr.h
avx2intrin.h
diff --git a/clang/lib/Headers/arm_cmse.h b/clang/lib/Headers/arm_cmse.h
new file mode 100644
index 000000000000..ecf50ecc5c8e
--- /dev/null
+++ b/clang/lib/Headers/arm_cmse.h
@@ -0,0 +1,217 @@
+//===---- arm_cmse.h - Arm CMSE support -----------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef __ARM_CMSE_H
+#define __ARM_CMSE_H
+
+#if (__ARM_FEATURE_CMSE & 0x1)
+#include <stddef.h>
+#include <stdint.h>
+
+#define __ARM_CMSE_SECURE_MODE (__ARM_FEATURE_CMSE & 0x2)
+#define CMSE_MPU_READWRITE 1 /* checks if readwrite_ok field is set */
+#define CMSE_AU_NONSECURE 2 /* checks if permissions have secure field unset */
+#define CMSE_MPU_UNPRIV 4 /* sets T flag on TT insrtuction */
+#define CMSE_MPU_READ 8 /* checks if read_ok field is set */
+#define CMSE_MPU_NONSECURE 16 /* sets A flag, checks if secure field unset */
+#define CMSE_NONSECURE (CMSE_AU_NONSECURE | CMSE_MPU_NONSECURE)
+
+#define cmse_check_pointed_object(p, f) \
+ cmse_check_address_range((p), sizeof(*(p)), (f))
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+typedef union {
+ struct cmse_address_info {
+#ifdef __ARM_BIG_ENDIAN
+ /* __ARM_BIG_ENDIAN */
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned idau_region : 8;
+ unsigned idau_region_valid : 1;
+ unsigned secure : 1;
+ unsigned nonsecure_readwrite_ok : 1;
+ unsigned nonsecure_read_ok : 1;
+#else
+ unsigned : 12;
+#endif
+ unsigned readwrite_ok : 1;
+ unsigned read_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region_valid : 1;
+#else
+ unsigned : 1;
+#endif
+ unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region : 8;
+#else
+ unsigned : 8;
+#endif
+ unsigned mpu_region : 8;
+
+#else /* __ARM_LITTLE_ENDIAN */
+ unsigned mpu_region : 8;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region : 8;
+#else
+ unsigned : 8;
+#endif
+ unsigned mpu_region_valid : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned sau_region_valid : 1;
+#else
+ unsigned : 1;
+#endif
+ unsigned read_ok : 1;
+ unsigned readwrite_ok : 1;
+#if (__ARM_CMSE_SECURE_MODE)
+ unsigned nonsecure_read_ok : 1;
+ unsigned nonsecure_readwrite_ok : 1;
+ unsigned secure : 1;
+ unsigned idau_region_valid : 1;
+ unsigned idau_region : 8;
+#else
+ unsigned : 12;
+#endif
+#endif /*__ARM_LITTLE_ENDIAN */
+ } flags;
+ unsigned value;
+} cmse_address_info_t;
+
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TT(__p);
+ return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTT(__p);
+ return __u;
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTA(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTA(__p);
+ return __u;
+}
+static cmse_address_info_t __attribute__((__always_inline__, __nodebug__))
+cmse_TTAT(void *__p) {
+ cmse_address_info_t __u;
+ __u.value = __builtin_arm_cmse_TTAT(__p);
+ return __u;
+}
+#endif
+
+#define cmse_TT_fptr(p) cmse_TT(__builtin_bit_cast(void *, (p)))
+#define cmse_TTT_fptr(p) cmse_TTT(__builtin_bit_cast(void *, (p)))
+
+#if __ARM_CMSE_SECURE_MODE
+#define cmse_TTA_fptr(p) cmse_TTA(__builtin_bit_cast(void *, (p)))
+#define cmse_TTAT_fptr(p) cmse_TTAT(__builtin_bit_cast(void *, (p)))
+#endif
+
+static void *__attribute__((__always_inline__))
+cmse_check_address_range(void *__pb, size_t __s, int __flags) {
+ uintptr_t __begin = (uintptr_t)__pb;
+ uintptr_t __end = __begin + __s - 1;
+
+ if (__end < __begin)
+ return NULL; /* wrap around check */
+
+ /* Check whether the range crosses a 32-bytes aligned address */
+ const int __single_check = (__begin ^ __end) < 0x20u;
+
+ /* execute the right variant of the TT instructions */
+ void *__pe = (void *)__end;
+ cmse_address_info_t __permb, __perme;
+ switch (__flags & (CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+ case 0:
+ __permb = cmse_TT(__pb);
+ __perme = __single_check ? __permb : cmse_TT(__pe);
+ break;
+ case CMSE_MPU_UNPRIV:
+ __permb = cmse_TTT(__pb);
+ __perme = __single_check ? __permb : cmse_TTT(__pe);
+ break;
+#if __ARM_CMSE_SECURE_MODE
+ case CMSE_MPU_NONSECURE:
+ __permb = cmse_TTA(__pb);
+ __perme = __single_check ? __permb : cmse_TTA(__pe);
+ break;
+ case CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE:
+ __permb = cmse_TTAT(__pb);
+ __perme = __single_check ? __permb : cmse_TTAT(__pe);
+ break;
+#endif
+ /* if CMSE_NONSECURE is specified w/o __ARM_CMSE_SECURE_MODE */
+ default:
+ return NULL;
+ }
+
+ /* check that the range does not cross MPU, SAU, or IDAU region boundaries */
+ if (__permb.value != __perme.value)
+ return NULL;
+#if !(__ARM_CMSE_SECURE_MODE)
+ /* CMSE_AU_NONSECURE is only supported when __ARM_FEATURE_CMSE & 0x2 */
+ if (__flags & CMSE_AU_NONSECURE)
+ return NULL;
+#endif
+
+ /* check the permission on the range */
+ switch (__flags & ~(CMSE_MPU_UNPRIV | CMSE_MPU_NONSECURE)) {
+#if (__ARM_CMSE_SECURE_MODE)
+ case CMSE_MPU_READ | CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+ case CMSE_MPU_READWRITE | CMSE_AU_NONSECURE:
+ return __permb.flags.nonsecure_readwrite_ok ? __pb : NULL;
+
+ case CMSE_MPU_READ | CMSE_AU_NONSECURE:
+ return __permb.flags.nonsecure_read_ok ? __pb : NULL;
+
+ case CMSE_AU_NONSECURE:
+ return __permb.flags.secure ? NULL : __pb;
+#endif
+ case CMSE_MPU_READ | CMSE_MPU_READWRITE:
+ case CMSE_MPU_READWRITE:
+ return __permb.flags.readwrite_ok ? __pb : NULL;
+
+ case CMSE_MPU_READ:
+ return __permb.flags.read_ok ? __pb : NULL;
+
+ default:
+ return NULL;
+ }
+}
+
+#if __ARM_CMSE_SECURE_MODE
+static int __attribute__((__always_inline__, __nodebug__))
+cmse_nonsecure_caller(void) {
+ return !((uintptr_t)__builtin_return_address(0) & 1);
+}
+
+#define cmse_nsfptr_create(p) \
+ __builtin_bit_cast(__typeof__(p), \
+ (__builtin_bit_cast(uintptr_t, p) & ~(uintptr_t)1))
+
+#define cmse_is_nsfptr(p) ((__builtin_bit_cast(uintptr_t, p) & 1) == 0)
+
+#endif /* __ARM_CMSE_SECURE_MODE */
+
+void __attribute__((__noreturn__)) cmse_abort(void);
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* (__ARM_FEATURE_CMSE & 0x1) */
+
+#endif /* __ARM_CMSE_H */
diff --git a/clang/test/CodeGen/arm-cmse-nonsecure.c b/clang/test/CodeGen/arm-cmse-nonsecure.c
new file mode 100644
index 000000000000..2a483a71f593
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse-nonsecure.c
@@ -0,0 +1,52 @@
+// RUN: %clang -mlittle-endian -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -mbig-endian -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+
+#include <arm_cmse.h>
+
+unsigned test_cmse_primitives(void *p) {
+// CHECK: define {{.*}} i32 @test_cmse_primitives
+ cmse_address_info_t tt_val, ttt_val;
+ unsigned sum;
+
+ tt_val = cmse_TT(p);
+ ttt_val = cmse_TTT(p);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: llvm.arm.cmse.tta
+// CHECK-NOT: llvm.arm.cmse.ttat
+
+ sum = tt_val.value;
+ sum += ttt_val.value;
+
+ sum += tt_val.flags.mpu_region;
+ sum += tt_val.flags.mpu_region_valid;
+ sum += tt_val.flags.read_ok;
+ sum += tt_val.flags.readwrite_ok;
+
+ return sum;
+}
+
+void *test_address_range(void *p) {
+// CHECK: define {{.*}} i8* @test_address_range
+ return cmse_check_address_range(p, 128, CMSE_MPU_UNPRIV
+ | CMSE_MPU_READWRITE
+ | CMSE_MPU_READ);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: llvm.arm.cmse.tta
+// CHECK-NOT: llvm.arm.cmse.ttat
+}
+
+typedef struct {
+ int x, y, z;
+} Point;
+
+void *test_pointed_object(void *p) {
+// CHECK: define {{.*}} i8* @test_pointed_object
+ Point *pt = (Point *)p;
+ cmse_check_pointed_object(pt, CMSE_MPU_READ);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK-NOT: call i32 @llvm.arm.cmse.tta
+// CHECK-NOT: call i32 @llvm.arm.cmse.ttat
+}
diff --git a/clang/test/CodeGen/arm-cmse-secure.c b/clang/test/CodeGen/arm-cmse-secure.c
new file mode 100644
index 000000000000..716887254e57
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse-secure.c
@@ -0,0 +1,66 @@
+// RUN: %clang -mlittle-endian -mcmse -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+// RUN: %clang -mbig-endian -mcmse -target thumbv8m.base-eabi -emit-llvm -S -o - %s | FileCheck %s
+
+#include <arm_cmse.h>
+
+unsigned test_cmse_primitives(void *p) {
+// CHECK: define {{.*}} i32 @test_cmse_primitives
+ cmse_address_info_t tt_val, ttt_val;
+ cmse_address_info_t tta_val, ttat_val;
+ unsigned sum;
+
+ tt_val = cmse_TT(p);
+ ttt_val = cmse_TTT(p);
+ tta_val = cmse_TTA(p);
+ ttat_val = cmse_TTAT(p);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+
+ sum = tt_val.value;
+ sum += ttt_val.value;
+ sum += tta_val.value;
+ sum += ttat_val.value;
+
+ sum += tt_val.flags.mpu_region;
+ sum += tt_val.flags.sau_region;
+ sum += tt_val.flags.mpu_region_valid;
+ sum += tt_val.flags.sau_region_valid;
+ sum += tt_val.flags.read_ok;
+ sum += tt_val.flags.readwrite_ok;
+ sum += tt_val.flags.nonsecure_read_ok;
+ sum += tt_val.flags.nonsecure_readwrite_ok;
+ sum += tt_val.flags.secure;
+ sum += tt_val.flags.idau_region_valid;
+ sum += tt_val.flags.idau_region;
+
+ return sum;
+}
+
+void *test_address_range(void *p) {
+// CHECK: define {{.*}} i8* @test_address_range
+ return cmse_check_address_range(p, 128, CMSE_MPU_UNPRIV
+ | CMSE_MPU_NONSECURE
+ | CMSE_MPU_READWRITE);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+}
+
+typedef struct {
+ int x, y, z;
+} Point;
+
+void *test_pointed_object(void *p) {
+// CHECK: define {{.*}} i8* @test_pointed_object
+ Point *pt = (Point *)p;
+ cmse_check_pointed_object(pt, CMSE_NONSECURE
+ | CMSE_MPU_READ
+ | CMSE_AU_NONSECURE);
+// CHECK: call i32 @llvm.arm.cmse.tt
+// CHECK: call i32 @llvm.arm.cmse.ttt
+// CHECK: call i32 @llvm.arm.cmse.tta
+// CHECK: call i32 @llvm.arm.cmse.ttat
+}
diff --git a/clang/test/CodeGen/arm-cmse.c b/clang/test/CodeGen/arm-cmse.c
new file mode 100644
index 000000000000..0f8247748ddc
--- /dev/null
+++ b/clang/test/CodeGen/arm-cmse.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-none-eabi -O1 -emit-llvm %s -o - | FileCheck %s
+int test_cmse_TT(void *p){
+ return __builtin_arm_cmse_TT(p);
+ // CHECK: call i32 @llvm.arm.cmse.tt(i8* %{{.*}})
+}
+
+int test_cmse_TTT(void *p){
+ return __builtin_arm_cmse_TTT(p);
+ // CHECK: call i32 @llvm.arm.cmse.ttt(i8* %{{.*}})
+}
+
+int test_cmse_TTA(void *p){
+ return __builtin_arm_cmse_TTA(p);
+ // CHECK: call i32 @llvm.arm.cmse.tta(i8* %{{.*}})
+}
+
+int test_cmse_TTAT(void *p){
+ return __builtin_arm_cmse_TTAT(p);
+ // CHECK: call i32 @llvm.arm.cmse.ttat(i8* %{{.*}})
+}
diff --git a/clang/test/Headers/arm-cmse-header-ns.c b/clang/test/Headers/arm-cmse-header-ns.c
new file mode 100644
index 000000000000..a6e63ef84149
--- /dev/null
+++ b/clang/test/Headers/arm-cmse-header-ns.c
@@ -0,0 +1,27 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only %s 2>&1 | FileCheck --check-prefix=CHECK-c %s
+// RUN: not %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only -x c++ %s 2>&1 | FileCheck --check-prefix=CHECK-cpp %s
+
+#include <arm_cmse.h>
+
+typedef void (*callback_t)(void);
+
+void func(callback_t fptr, void *p)
+{
+ cmse_TT(p);
+ cmse_TTT(p);
+ cmse_TT_fptr(fptr);
+ cmse_TTT_fptr(fptr);
+
+ cmse_TTA(p);
+ cmse_TTAT(p);
+ cmse_TTA_fptr(fptr);
+ cmse_TTAT_fptr(fptr);
+// CHECK-c: warning: implicit declaration of function 'cmse_TTA'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTAT'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTA_fptr'
+// CHECK-c: warning: implicit declaration of function 'cmse_TTAT_fptr'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTA'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTAT'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTA_fptr'
+// CHECK-cpp: error: use of undeclared identifier 'cmse_TTAT_fptr'
+}
diff --git a/clang/test/Headers/arm-cmse-header.c b/clang/test/Headers/arm-cmse-header.c
new file mode 100644
index 000000000000..862572d8adcd
--- /dev/null
+++ b/clang/test/Headers/arm-cmse-header.c
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only -ffreestanding %s -verify -mcmse
+// RUN: %clang_cc1 -triple thumbv8m.base-eabi -fsyntax-only -ffreestanding -x c++ %s -verify -mcmse
+// expected-no-diagnostics
+
+#include <arm_cmse.h>
+
+typedef void (*callback_t)(void);
+
+void func(callback_t fptr, void *p)
+{
+ cmse_TT(p);
+ cmse_TTT(p);
+ cmse_TTA(p);
+ cmse_TTAT(p);
+
+ cmse_TT_fptr(fptr);
+ cmse_TTT_fptr(fptr);
+ cmse_TTA_fptr(fptr);
+ cmse_TTAT_fptr(fptr);
+}
More information about the cfe-commits
mailing list