// System Registers
BUILTIN(__builtin_arm_rsr, "UicC*", "nc")
BUILTIN(__builtin_arm_rsr64, "WUicC*", "nc")
-BUILTIN(__builtin_arm_rsr128, "LLLUicC*", "nc")
+TARGET_BUILTIN(__builtin_arm_rsr128, "LLLUicC*", "nc", "d128")
BUILTIN(__builtin_arm_rsrp, "v*cC*", "nc")
BUILTIN(__builtin_arm_wsr, "vcC*Ui", "nc")
BUILTIN(__builtin_arm_wsr64, "vcC*WUi", "nc")
-BUILTIN(__builtin_arm_wsr128, "vcC*LLLUi", "nc")
+TARGET_BUILTIN(__builtin_arm_wsr128, "vcC*LLLUi", "nc", "d128")
BUILTIN(__builtin_arm_wsrp, "vcC*vC*", "nc")
// MSVC
/* 10.1 Special register intrinsics */
#define __arm_rsr(sysreg) __builtin_arm_rsr(sysreg)
#define __arm_rsr64(sysreg) __builtin_arm_rsr64(sysreg)
-#if __ARM_FEATURE_SYSREG128
#define __arm_rsr128(sysreg) __builtin_arm_rsr128(sysreg)
-#endif
#define __arm_rsrp(sysreg) __builtin_arm_rsrp(sysreg)
#define __arm_rsrf(sysreg) __builtin_bit_cast(float, __arm_rsr(sysreg))
#define __arm_rsrf64(sysreg) __builtin_bit_cast(double, __arm_rsr64(sysreg))
#define __arm_wsr(sysreg, v) __builtin_arm_wsr(sysreg, v)
#define __arm_wsr64(sysreg, v) __builtin_arm_wsr64(sysreg, v)
-#if __ARM_FEATURE_SYSREG128
#define __arm_wsr128(sysreg, v) __builtin_arm_wsr128(sysreg, v)
-#endif
#define __arm_wsrp(sysreg, v) __builtin_arm_wsrp(sysreg, v)
#define __arm_wsrf(sysreg, v) __arm_wsr(sysreg, __builtin_bit_cast(uint32_t, v))
#define __arm_wsrf64(sysreg, v) __arm_wsr64(sysreg, __builtin_bit_cast(uint64_t, v))
}
if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
- BuiltinID == AArch64::BI__builtin_arm_wsr64)
+ BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
// Memory Tagging Extensions (MTE) Intrinsics
BuiltinID == ARM::BI__builtin_arm_wsrp;
bool IsAArch64Builtin = BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
BuiltinID == AArch64::BI__builtin_arm_wsr64 ||
+ BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128 ||
BuiltinID == AArch64::BI__builtin_arm_rsr ||
BuiltinID == AArch64::BI__builtin_arm_rsrp ||
BuiltinID == AArch64::BI__builtin_arm_wsr ||
return Diag(TheCall->getBeginLoc(), diag::err_arm_invalid_specialreg)
<< Arg->getSourceRange();
} else if (IsAArch64Builtin && 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.
+ // This code validates writes to PSTATE registers.
+
+ // Not a write.
if (TheCall->getNumArgs() != 2)
return false;
- std::string RegLower = Reg.lower();
- if (RegLower != "spsel" && RegLower != "daifset" && RegLower != "daifclr" &&
- RegLower != "pan" && RegLower != "uao")
+ // The 128-bit system register accesses do not touch PSTATE.
+ if (BuiltinID == AArch64::BI__builtin_arm_rsr128 ||
+ BuiltinID == AArch64::BI__builtin_arm_wsr128)
return false;
- return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15);
+ // These are the named PSTATE accesses using "MSR (immediate)" instructions,
+ // along with the upper limit on the immediates allowed.
+ auto MaxLimit = llvm::StringSwitch<std::optional<unsigned>>(Reg)
+ .CaseLower("spsel", 15)
+ .CaseLower("daifclr", 15)
+ .CaseLower("daifset", 15)
+ .CaseLower("pan", 15)
+ .CaseLower("uao", 15)
+ .CaseLower("dit", 15)
+ .CaseLower("ssbs", 15)
+ .CaseLower("tco", 15)
+ .CaseLower("allint", 1)
+ .CaseLower("pm", 1)
+ .Default(std::nullopt);
+
+ // If this is not a named PSTATE, just continue without validating, as this
+ // will be lowered to an "MSR (register)" instruction directly
+ if (!MaxLimit)
+ return false;
+
+ // Here we only allow constants in the range for that pstate, as required by
+ // the ACLE.
+ //
+ // While clang also accepts the names of system registers in its ACLE
+ // intrinsics, we prevent this with the PSTATE names used in MSR (immediate)
+ // as the value written via a register is different to the value used as an
+ // immediate to have the same effect. e.g., for the instruction `msr tco,
+ // x0`, it is bit 25 of register x0 that is written into PSTATE.TCO, but
+ // with `msr tco, #imm`, it is bit 0 of xN that is written into PSTATE.TCO.
+ //
+ // If a programmer wants to codegen the MSR (register) form of `msr tco,
+ // xN`, they can still do so by specifying the register using five
+ // colon-separated numbers in a string.
+ return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit);
}
return false;
--- /dev/null
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +v8a -fsyntax-only -verify -emit-llvm -o - %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +d128 -fsyntax-only -verify=d128 -emit-llvm -o - %s
+
+// REQUIRES: aarch64-registered-target
+
+// Test that functions with the correct target attributes can use the correct
+// system-register intriniscs.
+
+// All the calls below are valid if you have -target-feature +d128
+// d128-no-diagnostics
+
+#include <arm_acle.h>
+
+void anytarget(void) {
+ unsigned x = __arm_rsr("1:2:3:4:5");
+ __arm_wsr("1:2:3:4:5", x);
+ unsigned long y = __arm_rsr64("1:2:3:4:5");
+ __arm_wsr64("1:2:3:4:5", y);
+ void *p = __arm_rsrp("1:2:3:4:5");
+ __arm_wsrp("1:2:3:4:5", p);
+}
+
+__attribute__((target("d128")))
+void d128target(void) {
+ __uint128_t x = __arm_rsr128("1:2:3:4:5");
+ __arm_wsr128("1:2:3:4:5", x);
+}
+
+void notd128target(void) {
+ __uint128_t x = __arm_rsr128("1:2:3:4:5"); // expected-error {{needs target feature d128}}
+ __arm_wsr128("1:2:3:4:5", x); // expected-error {{needs target feature d128}}
+}
__builtin_arm_wsr64("sysreg", v);
}
+void wsr128_1(__uint128_t v) {
+ __builtin_arm_wsr128("sysreg", v);
+}
+
unsigned rsr_1(void) {
return __builtin_arm_rsr("sysreg");
}
return __builtin_arm_rsr64("sysreg");
}
+__uint128_t rsr128_1(void) {
+ return __builtin_arm_rsr128("sysreg");
+}
+
void wsr_2(unsigned v) {
__builtin_arm_wsr("0:1:2:3:4", v);
}
return __builtin_arm_rsr64("0:1:15:15:4");
}
+__uint128_t rsr128_2(void) {
+ return __builtin_arm_rsr128("0:1:15:15:4");
+}
+
void wsr_3(unsigned v) {
__builtin_arm_wsr("0:1:2", v); //expected-error {{invalid special register for builtin}}
}
__builtin_arm_wsr64("0:1:2", v); //expected-error {{invalid special register for builtin}}
}
+void wsr128_3(__uint128_t v) {
+ __builtin_arm_wsr128("0:1:2", v); //expected-error {{invalid special register for builtin}}
+}
+
unsigned rsr_3(void) {
return __builtin_arm_rsr("0:1:2"); //expected-error {{invalid special register for builtin}}
}
unsigned long rsr64_6(void) {
return __builtin_arm_rsr64("0:1:16:16:2"); //expected-error {{invalid special register for builtin}}
}
+
+__uint128_t rsr128_3(void) {
+ return __builtin_arm_rsr128("0:1:2"); //expected-error {{invalid special register for builtin}}
+}
+
+__uint128_t rsr128_4(void) {
+ return __builtin_arm_rsr128("0:1:2:3:8"); //expected-error {{invalid special register for builtin}}
+}
+
+__uint128_t rsr128_5(void) {
+ return __builtin_arm_rsr128("0:8:2:3:4"); //expected-error {{invalid special register for builtin}}
+}
+
+__uint128_t rsr128_6(void) {
+ return __builtin_arm_rsr128("0:1:16:16:2"); //expected-error {{invalid special register for builtin}}
+}
+
+void wsr_4(void) {
+ __builtin_arm_wsr("spsel", 15);
+ __builtin_arm_wsr("daifclr", 15);
+ __builtin_arm_wsr("daifset", 15);
+ __builtin_arm_wsr("pan", 15);
+ __builtin_arm_wsr("uao", 15);
+ __builtin_arm_wsr("dit", 15);
+ __builtin_arm_wsr("ssbs", 15);
+ __builtin_arm_wsr("tco", 15);
+
+ __builtin_arm_wsr("allint", 1);
+ __builtin_arm_wsr("pm", 1);
+}
+
+void wsr64_4(void) {
+ __builtin_arm_wsr("spsel", 15);
+ __builtin_arm_wsr("daifclr", 15);
+ __builtin_arm_wsr("daifset", 15);
+ __builtin_arm_wsr("pan", 15);
+ __builtin_arm_wsr("uao", 15);
+ __builtin_arm_wsr("dit", 15);
+ __builtin_arm_wsr("ssbs", 15);
+ __builtin_arm_wsr("tco", 15);
+
+ __builtin_arm_wsr("allint", 1);
+ __builtin_arm_wsr("pm", 1);
+}
+
+void wsr_5(unsigned v) {
+ __builtin_arm_wsr("spsel", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("daifclr", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("daifset", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("pan", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("uao", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("dit", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("ssbs", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("tco", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("allint", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr("pm", v); // expected-error {{must be a constant integer}}
+}
+
+void wsr64_5(unsigned long v) {
+ __builtin_arm_wsr64("spsel", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("daifclr", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("daifset", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("pan", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("uao", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("dit", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("ssbs", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("tco", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("allint", v); // expected-error {{must be a constant integer}}
+ __builtin_arm_wsr64("pm", v); // expected-error {{must be a constant integer}}
+}
+
+void wsr_6(void) {
+ __builtin_arm_wsr("spsel", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("daifclr", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("daifset", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("pan", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("uao", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("dit", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("ssbs", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("tco", 16); // expected-error {{outside the valid range}}
+
+ __builtin_arm_wsr("allint", 2); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr("pm", 2); // expected-error {{outside the valid range}}
+}
+
+void wsr64_6(void) {
+ __builtin_arm_wsr64("spsel", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("daifclr", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("daifset", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("pan", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("uao", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("dit", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("ssbs", 16); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("tco", 16); // expected-error {{outside the valid range}}
+
+ __builtin_arm_wsr64("allint", 2); // expected-error {{outside the valid range}}
+ __builtin_arm_wsr64("pm", 2); // expected-error {{outside the valid range}}
+}