This patch implements clang support for the ACLE special register intrinsics in 
section 10.1, __arm_{w,r}sr{,p,64}.

This includes arm_acle.h definitions with builtins and codegen to support 
these, the intrinsics are implemented by generating read/write_register calls 
which get appropriately lowered in the backend based on the register string 
provided. SemaChecking is also implemented to fault invalid parameters, however 
SemaChecking currently only supports checking in when the register string is in 
an encoded form, e.g. "cp1:2:c3:c4:5", that the encoding is valid. Otherwise, 
checking just assumes that the string is a special register value, e.g. "CPSR"; 
this means that if the register value passed is not a valid special register 
value, it passes checking and reports an error in the backend when attempting 
to lower the read/write_register intrinsic. I would like to have more checking 
on these values in the frontend to provide more useful diagnostics but couldn't 
think of a clean and nice way of doing it.

http://reviews.llvm.org/D9697

Files:
  include/clang/Basic/BuiltinsAArch64.def
  include/clang/Basic/BuiltinsARM.def
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/Sema.h
  lib/CodeGen/CGBuiltin.cpp
  lib/Headers/arm_acle.h
  lib/Sema/SemaChecking.cpp
  test/CodeGen/arm_acle.c
  test/CodeGen/builtins-arm.c
  test/CodeGen/builtins-arm64.c
  test/Sema/aarch64-special-register.c
  test/Sema/arm-special-register.c

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/Basic/BuiltinsAArch64.def
===================================================================
--- include/clang/Basic/BuiltinsAArch64.def
+++ include/clang/Basic/BuiltinsAArch64.def
@@ -53,4 +53,12 @@
 // Prefetch
 BUILTIN(__builtin_arm_prefetch, "vvC*UiUiUiUi", "nc")
 
+// System Registers
+BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
+BUILTIN(__builtin_arm_rsr64, "LUicC*", "nc")
+BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
+BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
+BUILTIN(__builtin_arm_wsr64, "vcC*LUi", "nc")
+BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
+
 #undef BUILTIN
Index: include/clang/Basic/BuiltinsARM.def
===================================================================
--- include/clang/Basic/BuiltinsARM.def
+++ include/clang/Basic/BuiltinsARM.def
@@ -84,6 +84,14 @@
 // Prefetch
 BUILTIN(__builtin_arm_prefetch, "vvC*UiUi", "nc")
 
+// System registers (ACLE)
+BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
+BUILTIN(__builtin_arm_rsr64, "LLUicC*", "nc")
+BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
+BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
+BUILTIN(__builtin_arm_wsr64, "vcC*LLUi", "nc")
+BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
+
 // MSVC
 LANGBUILTIN(__emit, "vIUiC", "", ALL_MS_LANGUAGES)
 
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -108,6 +108,7 @@
 def err_ice_too_large : Error<
   "integer constant expression evaluates to value %0 that cannot be "
   "represented in a %1-bit %select{signed|unsigned}2 integer type">;
+def err_expr_not_string_literal : Error<"expression is not a string literal">;
 
 // Semantic analysis of constant literals.
 def ext_predef_outside_function : Warning<
@@ -424,6 +425,7 @@
   "incompatible redeclaration of library function %0">,
   InGroup<DiagGroup<"incompatible-library-redeclaration">>;
 def err_builtin_definition : Error<"definition of builtin function %0">;
+def err_arm_invalid_specialreg : Error<"invalid special register for builtin">;
 def warn_builtin_unknown : Warning<"use of unknown builtin %0">,
   InGroup<ImplicitFunctionDeclare>, DefaultError;
 def warn_dyn_class_memaccess : Warning<
Index: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ include/clang/Sema/Sema.h
@@ -8553,6 +8553,9 @@
                               llvm::APSInt &Result);
   bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum,
                                    int Low, int High);
+  bool SemaBuiltinARMSpecialReg(CallExpr *TheCall, int ArgNum,
+                                unsigned ExpectedFieldNum, bool AllowName,
+                                bool isAArch64);
 
 public:
   enum FormatStringType {
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -3478,6 +3478,49 @@
     }
   }
 
+  if (BuiltinID == ARM::BI__builtin_arm_rsr ||
+      BuiltinID == ARM::BI__builtin_arm_rsr64 ||
+      BuiltinID == ARM::BI__builtin_arm_rsrp ||
+      BuiltinID == ARM::BI__builtin_arm_wsr ||
+      BuiltinID == ARM::BI__builtin_arm_wsr64 ||
+      BuiltinID == ARM::BI__builtin_arm_wsrp) {
+
+    const Expr *SysRegStrExpr = E->getArg(0)->IgnoreParenCasts();
+    StringRef SysReg = cast<StringLiteral>(SysRegStrExpr)->getString();
+    bool IsRead = BuiltinID == ARM::BI__builtin_arm_rsr ||
+                  BuiltinID == ARM::BI__builtin_arm_rsr64 ||
+                  BuiltinID == ARM::BI__builtin_arm_rsrp;
+    bool Is64Bit = BuiltinID == ARM::BI__builtin_arm_rsr64 ||
+                   BuiltinID == ARM::BI__builtin_arm_wsr64;
+
+    llvm::Metadata *Ops[] = {llvm::MDString::get(CGM.getLLVMContext(), SysReg)};
+    llvm::MDNode *RegName = llvm::MDNode::get(CGM.getLLVMContext(), Ops);
+    llvm::Value *Metadata =
+                      llvm::MetadataAsValue::get(CGM.getLLVMContext(), RegName);
+
+    llvm::Type *Types[] = { Is64Bit ? Int64Ty : Int32Ty };
+
+    if (IsRead) {
+      llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
+      llvm::Value *Call = Builder.CreateCall(F, Metadata);
+
+      if (BuiltinID == ARM::BI__builtin_arm_rsrp)
+        // Have i32 result (Call) but want to return a VoidPtrTy (i8*).
+        return Builder.CreateIntToPtr(Call, VoidPtrTy);
+
+      return Call;
+    }
+
+    llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
+
+    llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1));
+    if (BuiltinID == ARM::BI__builtin_arm_wsrp)
+      // Have ptr argument but want to pass i32 value to write.
+      ArgValue = Builder.CreatePtrToInt(ArgValue, Int32Ty);
+
+    return Builder.CreateCall2(F, Metadata, ArgValue);
+  }
+
   SmallVector<Value*, 4> Ops;
   llvm::Value *Align = nullptr;
   for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++) {
@@ -4239,6 +4282,55 @@
     return Builder.CreateCall2(F, Arg0, Arg1);
   }
 
+  if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
+      BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
+      BuiltinID == AArch64::BI__builtin_arm_rsrp ||
+      BuiltinID == AArch64::BI__builtin_arm_wsr ||
+      BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+      BuiltinID == AArch64::BI__builtin_arm_wsrp) {
+    const Expr *SysRegStrExpr = E->getArg(0)->IgnoreParenCasts();
+    StringRef SysReg = cast<StringLiteral>(SysRegStrExpr)->getString();
+
+    bool IsRead = BuiltinID == AArch64::BI__builtin_arm_rsr ||
+                  BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
+                  BuiltinID == AArch64::BI__builtin_arm_rsrp;
+
+    llvm::Metadata *Ops[] = {llvm::MDString::get(CGM.getLLVMContext(), SysReg)};
+    llvm::MDNode *RegName = llvm::MDNode::get(CGM.getLLVMContext(), Ops);
+    llvm::Value* Metadata =
+                      llvm::MetadataAsValue::get(CGM.getLLVMContext(), RegName);
+    llvm::Type *Types[] = { Int64Ty };
+
+    if (IsRead) {
+      llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::read_register, Types);
+      llvm::Value *Call = Builder.CreateCall(F, Metadata);
+
+      if (BuiltinID == AArch64::BI__builtin_arm_rsr)
+        // Read into 64 bit register via read register
+        // and then truncate result to 32 bit.
+        Call = Builder.CreateTrunc(Call, Int32Ty);
+
+      if (BuiltinID == AArch64::BI__builtin_arm_rsrp)
+        // Have i64 result (Call) but want to return a VoidPtrTy (i8*).
+        return Builder.CreateIntToPtr(Call, VoidPtrTy);
+
+      return Call;
+    }
+
+    llvm::Value *F = CGM.getIntrinsic(llvm::Intrinsic::write_register, Types);
+    llvm::Value *ArgValue = EmitScalarExpr(E->getArg(1));
+
+    if (BuiltinID == AArch64::BI__builtin_arm_wsr)
+      // Extend 32 bit write value to 64 bit to pass to write.
+      ArgValue = Builder.CreateZExt(ArgValue, Int64Ty);
+
+    if (BuiltinID == AArch64::BI__builtin_arm_wsrp)
+      // Have ptr argument but want to pass i64 value to write.
+      ArgValue = Builder.CreatePtrToInt(ArgValue, Int64Ty);
+
+    return Builder.CreateCall2(F, Metadata, ArgValue);
+  }
+
   llvm::SmallVector<Value*, 4> Ops;
   for (unsigned i = 0, e = E->getNumArgs() - 1; i != e; i++)
     Ops.push_back(EmitScalarExpr(E->getArg(i)));
Index: lib/Headers/arm_acle.h
===================================================================
--- lib/Headers/arm_acle.h
+++ lib/Headers/arm_acle.h
@@ -289,6 +289,14 @@
 }
 #endif
 
+/* 10.1 Special register intrinsics */
+#define __arm_rsr(sysreg) __builtin_arm_rsr(sysreg)
+#define __arm_rsr64(sysreg) __builtin_arm_rsr64(sysreg)
+#define __arm_rsrp(sysreg) __builtin_arm_rsrp(sysreg)
+#define __arm_wsr(sysreg, v) __builtin_arm_wsr(sysreg, v)
+#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
+#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
+
 #if defined(__cplusplus)
 }
 #endif
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -833,6 +833,16 @@
       SemaBuiltinConstantArgRange(TheCall, 2, 0, 1);
   }
 
+  if (BuiltinID == ARM::BI__builtin_arm_rsr64 ||
+      BuiltinID == ARM::BI__builtin_arm_wsr64)
+    return SemaBuiltinARMSpecialReg(TheCall, 0, 3, false, false);
+
+  if (BuiltinID == ARM::BI__builtin_arm_rsr ||
+      BuiltinID == ARM::BI__builtin_arm_rsrp ||
+      BuiltinID == ARM::BI__builtin_arm_wsr ||
+      BuiltinID == ARM::BI__builtin_arm_wsrp)
+    return SemaBuiltinARMSpecialReg(TheCall, 0, 5, true, false);
+
   if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
     return true;
 
@@ -873,6 +883,16 @@
       SemaBuiltinConstantArgRange(TheCall, 4, 0, 1);
   }
 
+  if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
+      BuiltinID == AArch64::BI__builtin_arm_wsr64)
+    return SemaBuiltinARMSpecialReg(TheCall, 0, 5, false, true);
+
+  if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
+      BuiltinID == AArch64::BI__builtin_arm_rsrp ||
+      BuiltinID == AArch64::BI__builtin_arm_wsr ||
+      BuiltinID == AArch64::BI__builtin_arm_wsrp)
+    return SemaBuiltinARMSpecialReg(TheCall, 0, 5, true, true);
+
   if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall))
     return true;
 
@@ -2586,6 +2606,92 @@
   return false;
 }
 
+/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr
+/// TheCall is an ARM/AArch64 special register string literal.
+bool Sema::SemaBuiltinARMSpecialReg(CallExpr *TheCall, int ArgNum,
+                                    unsigned ExpectedFieldNum, bool AllowName,
+                                    bool IsAArch64) {
+  // We can't check the value of a dependent argument.
+  Expr *Arg = TheCall->getArg(ArgNum);
+  if (Arg->isTypeDependent() || Arg->isValueDependent())
+    return false;
+
+  // Check if the argument is a string literal.
+  if (!isa<StringLiteral>(Arg->IgnoreParenImpCasts()))
+    return Diag(TheCall->getLocStart(), diag::err_expr_not_string_literal)
+           << Arg->getSourceRange();
+
+  // Check the type of special register given.
+  StringRef Reg = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString();
+  SmallVector<StringRef, 6> Fields;
+  Reg.split(Fields, ":");
+
+  if (Fields.size() != ExpectedFieldNum && !(AllowName && Fields.size() == 1))
+    return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg)
+           << Arg->getSourceRange();
+
+  // If the string is the name of a register then we cannot check that it is
+  // valid here but if the string is of one the forms described in ACLE then we
+  // can check that the supplied fields are integers and within the valid
+  // ranges.
+  if (Fields.size() > 1) {
+    bool FiveFields = Fields.size() == 5;
+
+    bool ValidString = true;
+    if (!IsAArch64) {
+      ValidString &= Fields[0].startswith_lower("cp") ||
+                     Fields[0].startswith_lower("p");
+      if (ValidString)
+        Fields[0] =
+          Fields[0].drop_front(Fields[0].startswith_lower("cp") ? 2 : 1);
+
+      ValidString &= Fields[2].startswith_lower("c");
+      if (ValidString)
+        Fields[2] = Fields[2].drop_front(1);
+
+      if (FiveFields) {
+        ValidString &= Fields[3].startswith_lower("c");
+        if (ValidString)
+          Fields[3] = Fields[3].drop_front(1);
+      }
+    }
+
+    SmallVector<int, 5> Ranges = {15, 7, 15};
+    if (FiveFields)
+      Ranges = {IsAArch64 ? 1 : 15, 7, 7, 15, 15};
+
+    for (unsigned i=0; i<Fields.size(); ++i) {
+      int IntField;
+      ValidString &= !Fields[i].getAsInteger(10, IntField);
+      ValidString &= (IntField >= 0 && IntField <= Ranges[i]);
+    }
+
+    if (!ValidString)
+      return Diag(TheCall->getLocStart(), diag::err_arm_invalid_specialreg)
+             << Arg->getSourceRange();
+  }
+
+  if (IsAArch64 && Fields.size() == 1) {
+    // If the register name is one of those that appear in the condition below
+    // and the special register builtin being used is one of the write builtins,
+    // then we require that the argument provided for writing to the register
+    // is an integer constant expression. This is because it will be lowered to
+    // an MSR (immediate) instruction, so we need to know the immediate at
+    // compile time.
+    if (TheCall->getNumArgs() != 2)
+      return false;
+
+    std::string RegLower = Reg.lower();
+    if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" &&
+        RegLower != "pan" && RegLower != "uao")
+      return false;
+
+    return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+  }
+
+  return false;
+}
+
 /// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val).
 /// This checks that the target supports __builtin_longjmp and
 /// that val is a constant 1.
Index: test/CodeGen/arm_acle.c
===================================================================
--- test/CodeGen/arm_acle.c
+++ test/CodeGen/arm_acle.c
@@ -336,3 +336,69 @@
 uint32_t test_crc32cd(uint32_t a, uint64_t b) {
   return __crc32cd(a, b);
 }
+
+/* 10.1 Special register intrinsics */
+// ARM-LABEL: test_rsr
+// AArch64: call i64 @llvm.read_register.i64(metadata !3)
+// AArch32: call i32 @llvm.read_register.i32(metadata !3)
+uint32_t test_rsr() {
+#ifdef __ARM_32BIT_STATE
+  return __arm_rsr("cp1:2:c3:c4:5");
+#else
+  return __arm_rsr("1:2:3:4:5");
+#endif
+}
+
+// ARM-LABEL: test_rsr64
+// AArch64: call i64 @llvm.read_register.i64(metadata !3)
+// AArch32: call i64 @llvm.read_register.i64(metadata !4)
+uint64_t test_rsr64() {
+#ifdef __ARM_32BIT_STATE
+  return __arm_rsr64("cp1:2:c3");
+#else
+  return __arm_rsr64("1:2:3:4:5");
+#endif
+}
+
+// ARM-LABEL: test_rsrp
+// AArch64: call i64 @llvm.read_register.i64(metadata !4)
+// AArch32: call i32 @llvm.read_register.i32(metadata !5)
+void *test_rsrp() {
+  return __arm_rsrp("sysreg");
+}
+
+// ARM-LABEL: test_wsr
+// AArch64: call void @llvm.write_register.i64(metadata !3, i64 %0)
+// AArch32: call void @llvm.write_register.i32(metadata !3, i32 %v)
+void test_wsr(uint32_t v) {
+#ifdef __ARM_32BIT_STATE
+  __arm_wsr("cp1:2:c3:c4:5", v);
+#else
+  __arm_wsr("1:2:3:4:5", v);
+#endif
+}
+
+// ARM-LABEL: test_wsr64
+// AArch64: call void @llvm.write_register.i64(metadata !3, i64 %v)
+// AArch32: call void @llvm.write_register.i64(metadata !4, i64 %v)
+void test_wsr64(uint64_t v) {
+#ifdef __ARM_32BIT_STATE
+  __arm_wsr64("cp1:2:c3", v);
+#else
+  __arm_wsr64("1:2:3:4:5", v);
+#endif
+}
+
+// ARM-LABEL: test_wsrp
+// AArch64: call void @llvm.write_register.i64(metadata !4, i64 %0)
+// AArch32: call void @llvm.write_register.i32(metadata !5, i32 %0)
+void test_wsrp(void *v) {
+  __arm_wsrp("sysreg", v);
+}
+
+// AArch32: !3 = !{!"cp1:2:c3:c4:5"}
+// AArch32: !4 = !{!"cp1:2:c3"}
+// AArch32: !5 = !{!"sysreg"}
+
+// AArch64: !3 = !{!"1:2:3:4:5"}
+// AArch64: !4 = !{!"sysreg"}
Index: test/CodeGen/builtins-arm.c
===================================================================
--- test/CodeGen/builtins-arm.c
+++ test/CodeGen/builtins-arm.c
@@ -84,3 +84,42 @@
   __builtin_arm_prefetch(&i, 1, 0);
 // CHECK: call {{.*}} @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
 }
+
+unsigned rsr() {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = {{.*}} call i32 @llvm.read_register.i32(metadata !7)
+  // CHECK-NEXT: ret i32 [[V0]]
+  return __builtin_arm_rsr("cp1:2:c3:c4:5");
+}
+
+unsigned long long rsr64() {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = {{.*}} call i64 @llvm.read_register.i64(metadata !8)
+  // CHECK-NEXT: ret i64 [[V0]]
+  return __builtin_arm_rsr64("cp1:2:c3");
+}
+
+void *rsrp() {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = {{.*}} call i32 @llvm.read_register.i32(metadata !9)
+  // CHECK-NEXT: [[V1:[%A-Za-z0-9.]+]] = inttoptr i32 [[V0]] to i8*
+  // CHECK-NEXT: ret i8* [[V1]]
+  return __builtin_arm_rsrp("sysreg");
+}
+
+void wsr(unsigned v) {
+  // CHECK: call void @llvm.write_register.i32(metadata !7, i32 %v)
+  __builtin_arm_wsr("cp1:2:c3:c4:5", v);
+}
+
+void wsr64(unsigned long long v) {
+  // CHECK: call void @llvm.write_register.i64(metadata !8, i64 %v)
+  __builtin_arm_wsr64("cp1:2:c3", v);
+}
+
+void wsrp(void *v) {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = ptrtoint i8* %v to i32
+  // CHECK-NEXT: call void @llvm.write_register.i32(metadata !9, i32 [[V0]])
+  __builtin_arm_wsrp("sysreg", v);
+}
+
+// CHECK: !7 = !{!"cp1:2:c3:c4:5"}
+// CHECK: !8 = !{!"cp1:2:c3"}
+// CHECK: !9 = !{!"sysreg"}
Index: test/CodeGen/builtins-arm64.c
===================================================================
--- test/CodeGen/builtins-arm64.c
+++ test/CodeGen/builtins-arm64.c
@@ -43,3 +43,39 @@
   __builtin_arm_prefetch(0, 0, 0, 0, 0); // plil1keep
 // CHECK: call {{.*}} @llvm.prefetch(i8* null, i32 0, i32 3, i32 0)
 }
+
+unsigned rsr() {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = {{.*}} call i64 @llvm.read_register.i64(metadata !3)
+  // CHECK-NEXT: trunc i64 [[V0]] to i32
+  return __builtin_arm_rsr("1:2:3:4:5");
+}
+
+unsigned long rsr64() {
+  // CHECK: call i64 @llvm.read_register.i64(metadata !3)
+  return __builtin_arm_rsr64("1:2:3:4:5");
+}
+
+void *rsrp() {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = {{.*}} call i64 @llvm.read_register.i64(metadata !3)
+  // CHECK-NEXT: inttoptr i64 [[V0]] to i8*
+  return __builtin_arm_rsrp("1:2:3:4:5");
+}
+
+void wsr(unsigned v) {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = zext i32 %v to i64
+  // CHECK-NEXT: call void @llvm.write_register.i64(metadata !3, i64 [[V0]])
+  __builtin_arm_wsr("1:2:3:4:5", v);
+}
+
+void wsr64(unsigned long v) {
+  // CHECK: call void @llvm.write_register.i64(metadata !3, i64 %v)
+  __builtin_arm_wsr64("1:2:3:4:5", v);
+}
+
+void wsrp(void *v) {
+  // CHECK: [[V0:[%A-Za-z0-9.]+]] = ptrtoint i8* %v to i64
+  // CHECK-NEXT: call void @llvm.write_register.i64(metadata !3, i64 [[V0]])
+  __builtin_arm_wsrp("1:2:3:4:5", v);
+}
+
+// CHECK: !3 = !{!"1:2:3:4:5"}
Index: test/Sema/aarch64-special-register.c
===================================================================
--- /dev/null
+++ test/Sema/aarch64-special-register.c
@@ -0,0 +1,77 @@
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -triple aarch64 %s
+
+void string_literal(unsigned v) {
+  __builtin_arm_wsr(0, v); // expected-error {{expression is not a string literal}}
+}
+
+void wsr_1(unsigned v) {
+  __builtin_arm_wsr("sysreg", v);
+}
+
+void wsrp_1(void *v) {
+  __builtin_arm_wsrp("sysreg", v);
+}
+
+void wsr64_1(unsigned long v) {
+  __builtin_arm_wsr64("sysreg", v); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned rsr_1() {
+  return __builtin_arm_rsr("sysreg");
+}
+
+void *rsrp_1() {
+  return __builtin_arm_rsrp("sysreg");
+}
+
+unsigned long rsr64_1() {
+  return __builtin_arm_rsr64("sysreg"); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr_2(unsigned v) {
+  __builtin_arm_wsr("0:1:2:3:4", v);
+}
+
+void wsrp_2(void *v) {
+  __builtin_arm_wsrp("0:1:2:3:4", v);
+}
+
+void wsr64_2(unsigned long v) {
+  __builtin_arm_wsr64("0:1:2:3:4", v);
+}
+
+unsigned rsr_2() {
+  return __builtin_arm_rsr("0:1:2:3:4");
+}
+
+void *rsrp_2() {
+  return __builtin_arm_rsrp("0:1:2:3:4");
+}
+
+unsigned long rsr64_2() {
+  return __builtin_arm_rsr64("0:1:2:3:4");
+}
+
+void wsr_3(unsigned v) {
+  __builtin_arm_wsr("0:1:2", v); //expected-error {{invalid special register for builtin}}
+}
+
+void wsrp_3(void *v) {
+  __builtin_arm_wsrp("0:1:2", v); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr64_3(unsigned long v) {
+  __builtin_arm_wsr64("0:1:2", v); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned rsr_3() {
+  return __builtin_arm_rsr("0:1:2"); //expected-error {{invalid special register for builtin}}
+}
+
+void *rsrp_3() {
+  return __builtin_arm_rsrp("0:1:2"); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned long rsr64_3() {
+  return __builtin_arm_rsr64("0:1:2"); //expected-error {{invalid special register for builtin}}
+}
Index: test/Sema/arm-special-register.c
===================================================================
--- /dev/null
+++ test/Sema/arm-special-register.c
@@ -0,0 +1,89 @@
+// RUN: %clang_cc1 -ffreestanding -fsyntax-only -verify -triple arm %s
+
+void string_literal(unsigned v) {
+  __builtin_arm_wsr(0, v); // expected-error {{expression is not a string literal}}
+}
+
+void wsr_1(unsigned v) {
+  __builtin_arm_wsr("sysreg", v);
+}
+
+void wsrp_1(void *v) {
+  __builtin_arm_wsrp("sysreg", v);
+}
+
+void wsr64_1(unsigned long v) {
+  __builtin_arm_wsr64("sysreg", v); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned rsr_1() {
+  return __builtin_arm_rsr("sysreg");
+}
+
+void *rsrp_1() {
+  return __builtin_arm_rsrp("sysreg");
+}
+
+unsigned long rsr64_1() {
+  return __builtin_arm_rsr64("sysreg"); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr_2(unsigned v) {
+  __builtin_arm_wsr("cp0:1:c2:c3:4", v);
+}
+
+void wsrp_2(void *v) {
+  __builtin_arm_wsrp("cp0:1:c2:c3:4", v);
+}
+
+void wsr64_2(unsigned long v) {
+  __builtin_arm_wsr64("cp0:1:c2:c3:4", v); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned rsr_2() {
+  return __builtin_arm_rsr("cp0:1:c2:c3:4");
+}
+
+void *rsrp_2() {
+  return __builtin_arm_rsrp("cp0:1:c2:c3:4");
+}
+
+unsigned long rsr64_2() {
+  return __builtin_arm_rsr64("cp0:1:c2:c3:4"); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr_3(unsigned v) {
+  __builtin_arm_wsr("cp0:1:c2", v); //expected-error {{invalid special register for builtin}}
+}
+
+void wsrp_3(void *v) {
+  __builtin_arm_wsrp("cp0:1:c2", v); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr64_3(unsigned long v) {
+  __builtin_arm_wsr64("cp0:1:c2", v);
+}
+
+unsigned rsr_3() {
+  return __builtin_arm_rsr("cp0:1:c2"); //expected-error {{invalid special register for builtin}}
+}
+
+void *rsrp_3() {
+  return __builtin_arm_rsrp("cp0:1:c2"); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned long rsr64_3() {
+  return __builtin_arm_rsr64("cp0:1:c2");
+}
+
+unsigned rsr_4() {
+  return __builtin_arm_rsr("0:1:2:3:4"); //expected-error {{invalid special register for builtin}}
+}
+
+void *rsrp_4() {
+  return __builtin_arm_rsrp("0:1:2:3:4"); //expected-error {{invalid special register for builtin}}
+}
+
+unsigned long rsr64_4() {
+  return __builtin_arm_rsr64("0:1:2"); //expected-error {{invalid special register for builtin}}
+}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to