diff --git a/clang/include/clang/Basic/BuiltinsAArch64.def b/clang/include/clang/Basic/BuiltinsAArch64.def --- a/clang/include/clang/Basic/BuiltinsAArch64.def +++ b/clang/include/clang/Basic/BuiltinsAArch64.def @@ -82,11 +82,11 @@ // 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 diff --git a/clang/lib/Headers/arm_acle.h b/clang/lib/Headers/arm_acle.h --- a/clang/lib/Headers/arm_acle.h +++ b/clang/lib/Headers/arm_acle.h @@ -712,17 +712,13 @@ /* 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)) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3292,7 +3292,9 @@ } 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 @@ -8314,6 +8316,8 @@ 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 || @@ -8381,21 +8385,51 @@ 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>(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; diff --git a/clang/test/CodeGen/aarch64-sysregs-target.c b/clang/test/CodeGen/aarch64-sysregs-target.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/aarch64-sysregs-target.c @@ -0,0 +1,32 @@ +// 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 + +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}} +} diff --git a/clang/test/Sema/aarch64-special-register.c b/clang/test/Sema/aarch64-special-register.c --- a/clang/test/Sema/aarch64-special-register.c +++ b/clang/test/Sema/aarch64-special-register.c @@ -16,6 +16,10 @@ __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"); } @@ -28,6 +32,10 @@ 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); } @@ -52,6 +60,10 @@ 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}} } @@ -64,6 +76,10 @@ __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}} } @@ -99,3 +115,101 @@ 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}} +}