-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[AArch64] Add an option to get the TLS pointer from software #130932
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This patch adds an option to get the TLS pointer via a call to __aarch64_read_tp() (similar to __aeabi_read_tp on ARM). This mode is enabled when -mtp=soft is passed to clang. Necessary on Nintendo Horizon OS, which puts the TLS pointer at a calculated offset from TPIDR_EL0. Co-authored-by: Mary Guillemard <[email protected]> Signed-off-by: Sergi Granell Escalfet <[email protected]>
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be notified. If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers. If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-aarch64 Author: Sergi・セルジ (xerpi) ChangesThis patch adds an option to get the TLS pointer via a call to Necessary on Nintendo Horizon OS, which puts the TLS pointer at a calculated offset from TPIDR_EL0. Continuation of D61226. Full diff: https://github.com/llvm/llvm-project/pull/130932.diff 9 Files Affected:
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index e69cd6b833c3a..01ffaa9d8f8f4 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4732,7 +4732,7 @@ let Flags = [TargetSpecific] in {
def mtp_mode_EQ : Joined<["-"], "mtp=">, Group<m_arm_Features_Group>, Values<"soft,cp15,tpidrurw,tpidruro,tpidrprw,el0,el1,el2,el3,tpidr_el0,tpidr_el1,tpidr_el2,tpidr_el3,tpidrro_el0,auto">,
HelpText<"Thread pointer access method. "
"For AArch32: 'soft' uses a function call, or 'tpidrurw', 'tpidruro' or 'tpidrprw' use the three CP15 registers. 'cp15' is an alias for 'tpidruro'. "
- "For AArch64: 'tpidr_el0', 'tpidr_el1', 'tpidr_el2', 'tpidr_el3' or 'tpidrro_el0' use the five system registers. 'elN' is an alias for 'tpidr_elN'.">;
+ "For AArch64: 'soft' uses a function call, 'tpidr_el0', 'tpidr_el1', 'tpidr_el2', 'tpidr_el3' or 'tpidrro_el0' use the five system registers. 'elN' is an alias for 'tpidr_elN'.">;
def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for GCC compatibility
def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>;
def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>;
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 6e70effe9e325..4bab0c6f1d37f 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -192,6 +192,35 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
}
+// Select mode for reading thread pointer (-mtp=).
+aarch64::ReadTPMode aarch64::getReadTPMode(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple,
+ bool ForAS) {
+ Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ);
+ if (A) {
+ aarch64::ReadTPMode ThreadPointer =
+ llvm::StringSwitch<aarch64::ReadTPMode>(A->getValue())
+ .Case("soft", aarch64::ReadTPMode::Soft)
+ .Case("tpidr_el0", aarch64::ReadTPMode::TPIDR_EL0)
+ .Case("tpidr_el1", aarch64::ReadTPMode::TPIDR_EL1)
+ .Case("tpidr_el2", aarch64::ReadTPMode::TPIDR_EL2)
+ .Case("tpidr_el3", aarch64::ReadTPMode::TPIDR_EL3)
+ .Case("tpidrro_el0", aarch64::ReadTPMode::TPIDRRO_EL0)
+ .Case("el0", aarch64::ReadTPMode::TPIDR_EL0)
+ .Case("el1", aarch64::ReadTPMode::TPIDR_EL1)
+ .Case("el2", aarch64::ReadTPMode::TPIDR_EL2)
+ .Case("el3", aarch64::ReadTPMode::TPIDR_EL3)
+ .Default(ReadTPMode::Invalid);
+ if (ThreadPointer != ReadTPMode::Invalid)
+ return ThreadPointer;
+ if (StringRef(A->getValue()).empty())
+ D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args);
+ else
+ D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
+ }
+ return ReadTPMode::Invalid;
+}
+
void aarch64::getAArch64TargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
@@ -262,19 +291,20 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
// set to a feature list.
Extensions.toLLVMFeatureList(Features);
- if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
- StringRef Mtp = A->getValue();
- if (Mtp == "el3" || Mtp == "tpidr_el3")
- Features.push_back("+tpidr-el3");
- else if (Mtp == "el2" || Mtp == "tpidr_el2")
- Features.push_back("+tpidr-el2");
- else if (Mtp == "el1" || Mtp == "tpidr_el1")
- Features.push_back("+tpidr-el1");
- else if (Mtp == "tpidrro_el0")
- Features.push_back("+tpidrro-el0");
- else if (Mtp != "el0" && Mtp != "tpidr_el0")
- D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
- }
+ aarch64::ReadTPMode TPMode = getReadTPMode(D, Args, Triple, ForAS);
+
+ if (TPMode == Soft)
+ Features.push_back("+read-tp-soft");
+ else if (TPMode == TPIDR_EL1)
+ Features.push_back("+tpidr-el1");
+ else if (TPMode == TPIDR_EL2)
+ Features.push_back("+tpidr-el2");
+ else if (TPMode == TPIDR_EL3)
+ Features.push_back("+tpidr-el3");
+ else if (TPMode == TPIDRRO_EL0)
+ Features.push_back("+tpidrro-el0");
+ else if (TPMode != TPIDR_EL0 && TPMode != Soft)
+ D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
// Enable/disable straight line speculation hardening.
if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h
index 2057272867a17..d4eaa0c6a64e4 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.h
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h
@@ -20,6 +20,16 @@ namespace driver {
namespace tools {
namespace aarch64 {
+enum class ReadTPMode {
+ Invalid,
+ Soft,
+ TPIDR_EL0,
+ TPIDR_EL1,
+ TPIDR_EL2,
+ TPIDR_EL3,
+ TPIDRRO_EL0,
+};
+
void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features,
@@ -28,11 +38,14 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, llvm::opt::Arg *&A);
+ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple, bool ForAS);
+
void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args,
llvm::Triple &triple);
} // end namespace aarch64
-} // end namespace target
+} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/clang/test/Driver/aarch64-thread-pointer.c b/clang/test/Driver/aarch64-thread-pointer.c
index b1c6df4ac5e5d..6186a53bf3954 100644
--- a/clang/test/Driver/aarch64-thread-pointer.c
+++ b/clang/test/Driver/aarch64-thread-pointer.c
@@ -7,10 +7,13 @@
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=tpidr_el0 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
+// RUN: %clang --target=aarch64-linux -### -S %s -mtp=soft 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidrro-el0"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=tpidrro_el0 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_ROEL0 %s
@@ -18,6 +21,7 @@
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el1 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL1 %s
@@ -27,6 +31,7 @@
// ARMv8_THREAD_POINTER_EL1: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el2 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL2 %s
@@ -36,6 +41,7 @@
// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL2: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el3 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL3 %s
@@ -45,3 +51,12 @@
// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL3: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+read-tp-soft"
+
+// RUN: %clang --target=aarch64-linux -### -S %s -mtp=soft 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_SOFT %s
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidrro-el0"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el1"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el2"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_SOFT: "-target-feature" "+read-tp-soft"
diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
index 55a441b7d22b6..09ced5298cf61 100644
--- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
@@ -1487,6 +1487,17 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
return true;
}
+ case AArch64::GETbaseTLSsoft: {
+ Register DstReg = MI.getOperand(0).getReg();
+ MachineInstrBuilder MIB =
+ BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL))
+ .addExternalSymbol("__aarch64_read_tp")
+ .cloneMemRefs(MI);
+ transferImpOps(MI, MIB, MIB);
+ MI.eraseFromParent();
+ return true;
+ }
+
case AArch64::MOVi32imm:
return expandMOVImm(MBB, MBBI, 32);
case AArch64::MOVi64imm:
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 357f526d5e308..42069e6dc5c17 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -818,6 +818,10 @@ def FeatureUseFixedOverScalableIfEqualCost : SubtargetFeature<"use-fixed-over-sc
def FeatureAvoidLDAPUR : SubtargetFeature<"avoid-ldapur", "AvoidLDAPUR", "true",
"Prefer add+ldapr to offset ldapur">;
+// Read the TLS by calling __aarch64_read_tp
+def FeatureReadTpSoft : SubtargetFeature<"read-tp-soft", "ReadTpSoft",
+ "true", "Read thread pointer from __aarch64_read_tp" >;
+
//===----------------------------------------------------------------------===//
// Architectures.
//
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 6c61e3a613f6f..7a6ee0ab2bad8 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -395,6 +395,8 @@ def AArch64LocalRecover : SDNode<"ISD::LOCAL_RECOVER",
def AllowMisalignedMemAccesses : Predicate<"!Subtarget->requiresStrictAlign()">;
+def IsReadTPHard : Predicate<"!Subtarget->readTpSoft()">;
+def IsReadTPSoft : Predicate<"Subtarget->readTpSoft()">;
//===----------------------------------------------------------------------===//
// AArch64-specific DAG Nodes.
@@ -2121,7 +2123,18 @@ def : Pat<(AArch64mrs imm:$id),
// The thread pointer (on Linux, at least, where this has been implemented) is
// TPIDR_EL0.
def MOVbaseTLS : Pseudo<(outs GPR64:$dst), (ins),
- [(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>;
+ [(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>,
+ Requires<[IsReadTPHard]>;
+
+// __aarch64_read_tp preserves the registers x1-x7.
+// This is a pseudo inst so that we can get the encoding right,
+// complete with fixup for the aarch64_read_tp function.
+let isCall = 1,
+ Defs = [X0, X16, X17, LR], Uses = [SP] in {
+ def GETbaseTLSsoft : Pseudo<(outs), (ins),
+ [(set X0, AArch64threadpointer)]>, Sched<[WriteBr]>,
+ Requires<[IsReadTPSoft]>;
+}
// This gets lowered into a 24-byte instruction sequence
let Defs = [ X9, X16, X17, NZCV ], Size = 24 in {
diff --git a/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll b/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
index 679e4ac0bd27c..b796f59a54171 100644
--- a/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
@@ -4,6 +4,7 @@
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el1 | FileCheck --check-prefix=USEEL1 %s
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el2 | FileCheck --check-prefix=USEEL2 %s
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el3 | FileCheck --check-prefix=USEEL3 %s
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+read-tp-soft | FileCheck --check-prefix=SOFT %s
; Function Attrs: nounwind readnone
declare ptr @llvm.thread.pointer() #1
@@ -19,6 +20,8 @@ define ptr @thread_pointer() {
; USEEL2: mrs {{x[0-9]+}}, TPIDR_EL2
; USEEL3: thread_pointer:
; USEEL3: mrs {{x[0-9]+}}, TPIDR_EL3
+; SOFT: thread_pointer:
+; SOFT: bl __aarch64_read_tp
%1 = tail call ptr @llvm.thread.pointer()
ret ptr %1
}
diff --git a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
index c12730bd3b0d7..ccca5d7ff01a1 100644
--- a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
@@ -3,6 +3,7 @@
; RUN: llc < %s -debug-entry-values -mtriple=arm64-none-linux-gnu -stop-after=machineverifier -relocation-model=pic -aarch64-elf-ldtls-generation=1 < %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs -mattr=+read-tp-soft < %s | FileCheck --check-prefix=CHECK-TP-SOFT %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -verify-machineinstrs < %s | FileCheck --check-prefix=CHECK-NOLD %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-NOLD-RELOC %s
@@ -27,6 +28,12 @@ define i32 @test_generaldynamic() {
; CHECK-NEXT: .tlsdesccall general_dynamic_var
; CHECK-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: .tlsdesccall general_dynamic_var
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
@@ -36,6 +43,9 @@ define i32 @test_generaldynamic() {
; CHECK: mrs x[[TP:[0-9]+]], TPIDR_EL0
; CHECK: ldr w0, [x[[TP]], x0]
+; CHECK-TP-SOFT: mov x[[TMP:[0-9]+]], x0
+; CHECK-TP-SOFT: bl __aarch64_read_tp
+; CHECK-TP-SOFT: ldr w0, [x0, x[[TMP]]]
; CHECK-NOLD: mrs x[[TP:[0-9]+]], TPIDR_EL0
; CHECK-NOLD: ldr w0, [x[[TP]], x0]
@@ -62,8 +72,17 @@ define ptr @test_generaldynamic_addr() {
; CHECK-NEXT: .tlsdesccall general_dynamic_var
; CHECK-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: .tlsdesccall general_dynamic_var
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+
; CHECK: mrs [[TP:x[0-9]+]], TPIDR_EL0
; CHECK: add x0, [[TP]], x0
+; CHECK-TP-SOFT: mov x[[TMP:[0-9]+]], x0
+; CHECK-TP-SOFT: bl __aarch64_read_tp
+; CHECK-TP-SOFT: add x0, x0, x[[TMP]]
; CHECK-RELOC: R_AARCH64_TLSDESC_ADR_PAGE21
; CHECK-RELOC: R_AARCH64_TLSDESC_LD64_LO12
@@ -95,6 +114,16 @@ define i32 @test_localdynamic() {
; CHECK-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
; CHECK: ldr w0, [x[[TPIDR]], x[[TPOFF]]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: .tlsdesccall _TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT-NEXT: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
+; CHECK-TP-SOFT-DAG: bl __aarch64_read_tp
+; CHECK-TP-SOFT-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
+; CHECK-TP-SOFT: ldr w0, [x0, x[[TPOFF]]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:local_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var
@@ -131,6 +160,16 @@ define ptr @test_localdynamic_addr() {
; CHECK-DAG: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
; CHECK: add x0, x[[TPIDR]], x[[TPOFF]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: .tlsdesccall _TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT-NEXT: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
+; CHECK-TP-SOFT-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
+; CHECK-TP-SOFT-DAG: bl __aarch64_read_tp
+; CHECK-TP-SOFT: add x0, x0, x[[TPOFF]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:local_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var
|
@llvm/pr-subscribers-clang-driver Author: Sergi・セルジ (xerpi) ChangesThis patch adds an option to get the TLS pointer via a call to Necessary on Nintendo Horizon OS, which puts the TLS pointer at a calculated offset from TPIDR_EL0. Continuation of D61226. Full diff: https://github.com/llvm/llvm-project/pull/130932.diff 9 Files Affected:
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index e69cd6b833c3a..01ffaa9d8f8f4 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -4732,7 +4732,7 @@ let Flags = [TargetSpecific] in {
def mtp_mode_EQ : Joined<["-"], "mtp=">, Group<m_arm_Features_Group>, Values<"soft,cp15,tpidrurw,tpidruro,tpidrprw,el0,el1,el2,el3,tpidr_el0,tpidr_el1,tpidr_el2,tpidr_el3,tpidrro_el0,auto">,
HelpText<"Thread pointer access method. "
"For AArch32: 'soft' uses a function call, or 'tpidrurw', 'tpidruro' or 'tpidrprw' use the three CP15 registers. 'cp15' is an alias for 'tpidruro'. "
- "For AArch64: 'tpidr_el0', 'tpidr_el1', 'tpidr_el2', 'tpidr_el3' or 'tpidrro_el0' use the five system registers. 'elN' is an alias for 'tpidr_elN'.">;
+ "For AArch64: 'soft' uses a function call, 'tpidr_el0', 'tpidr_el1', 'tpidr_el2', 'tpidr_el3' or 'tpidrro_el0' use the five system registers. 'elN' is an alias for 'tpidr_elN'.">;
def mpure_code : Flag<["-"], "mpure-code">, Alias<mexecute_only>; // Alias for GCC compatibility
def mno_pure_code : Flag<["-"], "mno-pure-code">, Alias<mno_execute_only>;
def mtvos_version_min_EQ : Joined<["-"], "mtvos-version-min=">, Group<m_Group>;
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
index 6e70effe9e325..4bab0c6f1d37f 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp
@@ -192,6 +192,35 @@ getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
}
+// Select mode for reading thread pointer (-mtp=).
+aarch64::ReadTPMode aarch64::getReadTPMode(const Driver &D, const ArgList &Args,
+ const llvm::Triple &Triple,
+ bool ForAS) {
+ Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ);
+ if (A) {
+ aarch64::ReadTPMode ThreadPointer =
+ llvm::StringSwitch<aarch64::ReadTPMode>(A->getValue())
+ .Case("soft", aarch64::ReadTPMode::Soft)
+ .Case("tpidr_el0", aarch64::ReadTPMode::TPIDR_EL0)
+ .Case("tpidr_el1", aarch64::ReadTPMode::TPIDR_EL1)
+ .Case("tpidr_el2", aarch64::ReadTPMode::TPIDR_EL2)
+ .Case("tpidr_el3", aarch64::ReadTPMode::TPIDR_EL3)
+ .Case("tpidrro_el0", aarch64::ReadTPMode::TPIDRRO_EL0)
+ .Case("el0", aarch64::ReadTPMode::TPIDR_EL0)
+ .Case("el1", aarch64::ReadTPMode::TPIDR_EL1)
+ .Case("el2", aarch64::ReadTPMode::TPIDR_EL2)
+ .Case("el3", aarch64::ReadTPMode::TPIDR_EL3)
+ .Default(ReadTPMode::Invalid);
+ if (ThreadPointer != ReadTPMode::Invalid)
+ return ThreadPointer;
+ if (StringRef(A->getValue()).empty())
+ D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args);
+ else
+ D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
+ }
+ return ReadTPMode::Invalid;
+}
+
void aarch64::getAArch64TargetFeatures(const Driver &D,
const llvm::Triple &Triple,
const ArgList &Args,
@@ -262,19 +291,20 @@ void aarch64::getAArch64TargetFeatures(const Driver &D,
// set to a feature list.
Extensions.toLLVMFeatureList(Features);
- if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) {
- StringRef Mtp = A->getValue();
- if (Mtp == "el3" || Mtp == "tpidr_el3")
- Features.push_back("+tpidr-el3");
- else if (Mtp == "el2" || Mtp == "tpidr_el2")
- Features.push_back("+tpidr-el2");
- else if (Mtp == "el1" || Mtp == "tpidr_el1")
- Features.push_back("+tpidr-el1");
- else if (Mtp == "tpidrro_el0")
- Features.push_back("+tpidrro-el0");
- else if (Mtp != "el0" && Mtp != "tpidr_el0")
- D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
- }
+ aarch64::ReadTPMode TPMode = getReadTPMode(D, Args, Triple, ForAS);
+
+ if (TPMode == Soft)
+ Features.push_back("+read-tp-soft");
+ else if (TPMode == TPIDR_EL1)
+ Features.push_back("+tpidr-el1");
+ else if (TPMode == TPIDR_EL2)
+ Features.push_back("+tpidr-el2");
+ else if (TPMode == TPIDR_EL3)
+ Features.push_back("+tpidr-el3");
+ else if (TPMode == TPIDRRO_EL0)
+ Features.push_back("+tpidrro-el0");
+ else if (TPMode != TPIDR_EL0 && TPMode != Soft)
+ D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args);
// Enable/disable straight line speculation hardening.
if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {
diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.h b/clang/lib/Driver/ToolChains/Arch/AArch64.h
index 2057272867a17..d4eaa0c6a64e4 100644
--- a/clang/lib/Driver/ToolChains/Arch/AArch64.h
+++ b/clang/lib/Driver/ToolChains/Arch/AArch64.h
@@ -20,6 +20,16 @@ namespace driver {
namespace tools {
namespace aarch64 {
+enum class ReadTPMode {
+ Invalid,
+ Soft,
+ TPIDR_EL0,
+ TPIDR_EL1,
+ TPIDR_EL2,
+ TPIDR_EL3,
+ TPIDRRO_EL0,
+};
+
void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
const llvm::opt::ArgList &Args,
std::vector<llvm::StringRef> &Features,
@@ -28,11 +38,14 @@ void getAArch64TargetFeatures(const Driver &D, const llvm::Triple &Triple,
std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args,
const llvm::Triple &Triple, llvm::opt::Arg *&A);
+ReadTPMode getReadTPMode(const Driver &D, const llvm::opt::ArgList &Args,
+ const llvm::Triple &Triple, bool ForAS);
+
void setPAuthABIInTriple(const Driver &D, const llvm::opt::ArgList &Args,
llvm::Triple &triple);
} // end namespace aarch64
-} // end namespace target
+} // end namespace tools
} // end namespace driver
} // end namespace clang
diff --git a/clang/test/Driver/aarch64-thread-pointer.c b/clang/test/Driver/aarch64-thread-pointer.c
index b1c6df4ac5e5d..6186a53bf3954 100644
--- a/clang/test/Driver/aarch64-thread-pointer.c
+++ b/clang/test/Driver/aarch64-thread-pointer.c
@@ -7,10 +7,13 @@
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=tpidr_el0 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
+// RUN: %clang --target=aarch64-linux -### -S %s -mtp=soft 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL0 %s
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidrro-el0"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL0-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=tpidrro_el0 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_ROEL0 %s
@@ -18,6 +21,7 @@
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_ROEL0-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el1 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL1 %s
@@ -27,6 +31,7 @@
// ARMv8_THREAD_POINTER_EL1: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL1-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el2 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL2 %s
@@ -36,6 +41,7 @@
// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL2: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL2-NOT: "-target-feature" "+read-tp-soft"
// RUN: %clang --target=aarch64-linux -### -S %s -mtp=el3 2>&1 | \
// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_EL3 %s
@@ -45,3 +51,12 @@
// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+tpidr-el1"
// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+tpidr-el2"
// ARMv8_THREAD_POINTER_EL3: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_EL3-NOT: "-target-feature" "+read-tp-soft"
+
+// RUN: %clang --target=aarch64-linux -### -S %s -mtp=soft 2>&1 | \
+// RUN: FileCheck -check-prefix=ARMv8_THREAD_POINTER_SOFT %s
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidrro-el0"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el1"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el2"
+// ARMv8_THREAD_POINTER_SOFT-NOT: "-target-feature" "+tpidr-el3"
+// ARMv8_THREAD_POINTER_SOFT: "-target-feature" "+read-tp-soft"
diff --git a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
index 55a441b7d22b6..09ced5298cf61 100644
--- a/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ExpandPseudoInsts.cpp
@@ -1487,6 +1487,17 @@ bool AArch64ExpandPseudo::expandMI(MachineBasicBlock &MBB,
return true;
}
+ case AArch64::GETbaseTLSsoft: {
+ Register DstReg = MI.getOperand(0).getReg();
+ MachineInstrBuilder MIB =
+ BuildMI(MBB, MBBI, MI.getDebugLoc(), TII->get(AArch64::BL))
+ .addExternalSymbol("__aarch64_read_tp")
+ .cloneMemRefs(MI);
+ transferImpOps(MI, MIB, MIB);
+ MI.eraseFromParent();
+ return true;
+ }
+
case AArch64::MOVi32imm:
return expandMOVImm(MBB, MBBI, 32);
case AArch64::MOVi64imm:
diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td
index 357f526d5e308..42069e6dc5c17 100644
--- a/llvm/lib/Target/AArch64/AArch64Features.td
+++ b/llvm/lib/Target/AArch64/AArch64Features.td
@@ -818,6 +818,10 @@ def FeatureUseFixedOverScalableIfEqualCost : SubtargetFeature<"use-fixed-over-sc
def FeatureAvoidLDAPUR : SubtargetFeature<"avoid-ldapur", "AvoidLDAPUR", "true",
"Prefer add+ldapr to offset ldapur">;
+// Read the TLS by calling __aarch64_read_tp
+def FeatureReadTpSoft : SubtargetFeature<"read-tp-soft", "ReadTpSoft",
+ "true", "Read thread pointer from __aarch64_read_tp" >;
+
//===----------------------------------------------------------------------===//
// Architectures.
//
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 6c61e3a613f6f..7a6ee0ab2bad8 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -395,6 +395,8 @@ def AArch64LocalRecover : SDNode<"ISD::LOCAL_RECOVER",
def AllowMisalignedMemAccesses : Predicate<"!Subtarget->requiresStrictAlign()">;
+def IsReadTPHard : Predicate<"!Subtarget->readTpSoft()">;
+def IsReadTPSoft : Predicate<"Subtarget->readTpSoft()">;
//===----------------------------------------------------------------------===//
// AArch64-specific DAG Nodes.
@@ -2121,7 +2123,18 @@ def : Pat<(AArch64mrs imm:$id),
// The thread pointer (on Linux, at least, where this has been implemented) is
// TPIDR_EL0.
def MOVbaseTLS : Pseudo<(outs GPR64:$dst), (ins),
- [(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>;
+ [(set GPR64:$dst, AArch64threadpointer)]>, Sched<[WriteSys]>,
+ Requires<[IsReadTPHard]>;
+
+// __aarch64_read_tp preserves the registers x1-x7.
+// This is a pseudo inst so that we can get the encoding right,
+// complete with fixup for the aarch64_read_tp function.
+let isCall = 1,
+ Defs = [X0, X16, X17, LR], Uses = [SP] in {
+ def GETbaseTLSsoft : Pseudo<(outs), (ins),
+ [(set X0, AArch64threadpointer)]>, Sched<[WriteBr]>,
+ Requires<[IsReadTPSoft]>;
+}
// This gets lowered into a 24-byte instruction sequence
let Defs = [ X9, X16, X17, NZCV ], Size = 24 in {
diff --git a/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll b/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
index 679e4ac0bd27c..b796f59a54171 100644
--- a/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-builtins-linux.ll
@@ -4,6 +4,7 @@
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el1 | FileCheck --check-prefix=USEEL1 %s
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el2 | FileCheck --check-prefix=USEEL2 %s
; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+tpidr-el3 | FileCheck --check-prefix=USEEL3 %s
+; RUN: llc < %s -mtriple=aarch64-linux-gnu -mattr=+read-tp-soft | FileCheck --check-prefix=SOFT %s
; Function Attrs: nounwind readnone
declare ptr @llvm.thread.pointer() #1
@@ -19,6 +20,8 @@ define ptr @thread_pointer() {
; USEEL2: mrs {{x[0-9]+}}, TPIDR_EL2
; USEEL3: thread_pointer:
; USEEL3: mrs {{x[0-9]+}}, TPIDR_EL3
+; SOFT: thread_pointer:
+; SOFT: bl __aarch64_read_tp
%1 = tail call ptr @llvm.thread.pointer()
ret ptr %1
}
diff --git a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
index c12730bd3b0d7..ccca5d7ff01a1 100644
--- a/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
+++ b/llvm/test/CodeGen/AArch64/arm64-tls-dynamics.ll
@@ -3,6 +3,7 @@
; RUN: llc < %s -debug-entry-values -mtriple=arm64-none-linux-gnu -stop-after=machineverifier -relocation-model=pic -aarch64-elf-ldtls-generation=1 < %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -verify-machineinstrs -mattr=+read-tp-soft < %s | FileCheck --check-prefix=CHECK-TP-SOFT %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -aarch64-elf-ldtls-generation=1 -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-RELOC %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -verify-machineinstrs < %s | FileCheck --check-prefix=CHECK-NOLD %s
; RUN: llc -mtriple=arm64-none-linux-gnu -relocation-model=pic -filetype=obj < %s | llvm-objdump -r - | FileCheck --check-prefix=CHECK-NOLD-RELOC %s
@@ -27,6 +28,12 @@ define i32 @test_generaldynamic() {
; CHECK-NEXT: .tlsdesccall general_dynamic_var
; CHECK-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: .tlsdesccall general_dynamic_var
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
@@ -36,6 +43,9 @@ define i32 @test_generaldynamic() {
; CHECK: mrs x[[TP:[0-9]+]], TPIDR_EL0
; CHECK: ldr w0, [x[[TP]], x0]
+; CHECK-TP-SOFT: mov x[[TMP:[0-9]+]], x0
+; CHECK-TP-SOFT: bl __aarch64_read_tp
+; CHECK-TP-SOFT: ldr w0, [x0, x[[TMP]]]
; CHECK-NOLD: mrs x[[TP:[0-9]+]], TPIDR_EL0
; CHECK-NOLD: ldr w0, [x[[TP]], x0]
@@ -62,8 +72,17 @@ define ptr @test_generaldynamic_addr() {
; CHECK-NEXT: .tlsdesccall general_dynamic_var
; CHECK-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:general_dynamic_var
+; CHECK-TP-SOFT-NEXT: .tlsdesccall general_dynamic_var
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+
; CHECK: mrs [[TP:x[0-9]+]], TPIDR_EL0
; CHECK: add x0, [[TP]], x0
+; CHECK-TP-SOFT: mov x[[TMP:[0-9]+]], x0
+; CHECK-TP-SOFT: bl __aarch64_read_tp
+; CHECK-TP-SOFT: add x0, x0, x[[TMP]]
; CHECK-RELOC: R_AARCH64_TLSDESC_ADR_PAGE21
; CHECK-RELOC: R_AARCH64_TLSDESC_LD64_LO12
@@ -95,6 +114,16 @@ define i32 @test_localdynamic() {
; CHECK-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
; CHECK: ldr w0, [x[[TPIDR]], x[[TPOFF]]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: .tlsdesccall _TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT-NEXT: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
+; CHECK-TP-SOFT-DAG: bl __aarch64_read_tp
+; CHECK-TP-SOFT-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
+; CHECK-TP-SOFT: ldr w0, [x0, x[[TPOFF]]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:local_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var
@@ -131,6 +160,16 @@ define ptr @test_localdynamic_addr() {
; CHECK-DAG: mrs x[[TPIDR:[0-9]+]], TPIDR_EL0
; CHECK: add x0, x[[TPIDR]], x[[TPOFF]]
+; CHECK-TP-SOFT: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_]
+; CHECK-TP-SOFT-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:_TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: .tlsdesccall _TLS_MODULE_BASE_
+; CHECK-TP-SOFT-NEXT: blr [[CALLEE]]
+; CHECK-TP-SOFT-NEXT: add x[[TPOFF:[0-9]+]], x0, :dtprel_hi12:local_dynamic_var
+; CHECK-TP-SOFT-DAG: add x[[TPOFF]], x[[TPOFF]], :dtprel_lo12_nc:local_dynamic_var
+; CHECK-TP-SOFT-DAG: bl __aarch64_read_tp
+; CHECK-TP-SOFT: add x0, x0, x[[TPOFF]]
+
; CHECK-NOLD: adrp x[[TLSDESC_HI:[0-9]+]], :tlsdesc:local_dynamic_var
; CHECK-NOLD-NEXT: ldr [[CALLEE:x[0-9]+]], [x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var]
; CHECK-NOLD-NEXT: add x0, x[[TLSDESC_HI]], :tlsdesc_lo12:local_dynamic_var
|
The AArch64 ABI doesn't currently document an equivalent of I've very recently made a pull request to document the AArch64 TLS ABI ARM-software/abi-aa#311 it would be best to see if I can get an agreement with the GNU team about what we should call the function and what the PCS restrictions on it should be [*]. Please could you raise an issue in the ABI https://github.com/ARM-software/abi-aa/issues asking for it to be added? I can do that internally but it will help to know there is a real world use case. [*] The introduction of SVE has had some complications in some TLS resolver functions (https://inbox.sourceware.org/gcc/[email protected]/ and https://sourceware.org/pipermail/libc-alpha/2019-May/103540.html) that I need to write up in the ABI. In the case of a |
This patch adds an option to get the TLS pointer via a call to
__aarch64_read_tp()
(similar to__aeabi_read_tp()
on ARM).This mode is enabled when
-mtp=soft
is passed to clang.Necessary on Nintendo Switch Horizon OS, which puts the TLS pointer at a calculated offset from TPIDR_EL0.
Continuation of D61226.