From 312fcc116bc2d38d852ba1fd08c6840bf828ec36 Mon Sep 17 00:00:00 2001 From: Kristina Brooks Date: Thu, 18 Oct 2018 03:14:37 +0000 Subject: [PATCH] [X86] Support for the mno-tls-direct-seg-refs flag Allows to disable direct TLS segment access (%fs or %gs). GCC supports a similar flag, it can be useful in some circumstances, e.g. when a thread context block needs to be updated directly from user space. More info and specific use cases: https://bugs.llvm.org/show_bug.cgi?id=16145 There is another revision for clang as well. Related: D53102 All X86 CodeGen tests appear to pass: ``` [46/47] Running lit suite /SourceCache/llvm-trunk-8.0/test/CodeGen Testing Time: 23.17s Expected Passes : 3801 Expected Failures : 15 Unsupported Tests : 8021 ``` Reviewed by: Craig Topper. Patch by nruslan (Ruslan Nikolaev). Differential Revision: https://reviews.llvm.org/D53103 llvm-svn: 344723 --- llvm/docs/LangRef.rst | 4 +++ llvm/lib/Target/X86/X86ISelDAGToDAG.cpp | 6 ++++ llvm/test/CodeGen/X86/tls.ll | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+) diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index e977657..d396e3f 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -1450,6 +1450,10 @@ example: ``noredzone`` This attribute indicates that the code generator should not use a red zone, even if the target-specific ABI normally permits it. +``indirect-tls-seg-refs`` + This attribute indicates that the code generator should not use + direct TLS access through segment registers, even if the + target-specific ABI normally permits it. ``noreturn`` This function attribute indicates that the function never returns normally. This produces undefined behavior at runtime if the diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp index c06ad115..d6bcdcd 100644 --- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp +++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp @@ -165,6 +165,9 @@ namespace { /// If true, selector should try to optimize for minimum code size. bool OptForMinSize; + /// Disable direct TLS access through segment registers. + bool IndirectTlsSegRefs; + public: explicit X86DAGToDAGISel(X86TargetMachine &tm, CodeGenOpt::Level OptLevel) : SelectionDAGISel(tm, OptLevel), OptForSize(false), @@ -177,6 +180,8 @@ namespace { bool runOnMachineFunction(MachineFunction &MF) override { // Reset the subtarget each time through. Subtarget = &MF.getSubtarget(); + IndirectTlsSegRefs = MF.getFunction().hasFnAttribute( + "indirect-tls-seg-refs"); SelectionDAGISel::runOnMachineFunction(MF); return true; } @@ -981,6 +986,7 @@ bool X86DAGToDAGISel::matchLoadInAddress(LoadSDNode *N, X86ISelAddressMode &AM){ // For more information see http://people.redhat.com/drepper/tls.pdf if (ConstantSDNode *C = dyn_cast(Address)) if (C->getSExtValue() == 0 && AM.Segment.getNode() == nullptr && + !IndirectTlsSegRefs && (Subtarget->isTargetGlibc() || Subtarget->isTargetAndroid() || Subtarget->isTargetFuchsia())) switch (N->getPointerInfo().getAddrSpace()) { diff --git a/llvm/test/CodeGen/X86/tls.ll b/llvm/test/CodeGen/X86/tls.ll index ddfebcd..759f3d7 100644 --- a/llvm/test/CodeGen/X86/tls.ll +++ b/llvm/test/CodeGen/X86/tls.ll @@ -1,5 +1,7 @@ ; RUN: llc < %s -mtriple=i386-linux-gnu | FileCheck -check-prefix=X86_LINUX %s ; RUN: llc < %s -mtriple=x86_64-linux-gnu | FileCheck -check-prefix=X64_LINUX %s +; RUN: llc < %s -mtriple=i386-linux-gnu -fast-isel | FileCheck -check-prefix=X86_ISEL_LINUX %s +; RUN: llc < %s -mtriple=x86_64-linux-gnu -fast-isel | FileCheck -check-prefix=X64_ISEL_LINUX %s ; RUN: llc < %s -mtriple=i686-pc-win32 | FileCheck -check-prefix=X86_WIN %s ; RUN: llc < %s -mtriple=x86_64-pc-win32 | FileCheck -check-prefix=X64_WIN %s ; RUN: llc < %s -mtriple=i686-pc-windows-gnu | FileCheck -check-prefix=MINGW32 %s @@ -453,3 +455,59 @@ define i32* @f16() { ret i32* @i6 } + +; NOTE: Similar to f1() but with direct TLS segment access disabled +define i32 @f17() #0 { +; X86_LINUX-LABEL: f17: +; X86_LINUX: movl %gs:0, %eax +; X86_LINUX-NEXT: movl i1@NTPOFF(%eax), %eax +; X86_LINUX-NEXT: ret +; X64_LINUX-LABEL: f17: +; X64_LINUX: movq %fs:0, %rax +; X64_LINUX-NEXT: movl i1@TPOFF(%rax), %eax +; X64_LINUX-NEXT: ret +; X86_ISEL_LINUX-LABEL: f17: +; X86_ISEL_LINUX: movl %gs:0, %eax +; X86_ISEL_LINUX-NEXT: movl i1@NTPOFF(%eax), %eax +; X86_ISEL_LINUX-NEXT: ret +; X64_ISEL_LINUX-LABEL: f17: +; X64_ISEL_LINUX: movq %fs:0, %rax +; X64_ISEL_LINUX-NEXT: movl i1@TPOFF(%rax), %eax +; X64_ISEL_LINUX-NEXT: ret + +entry: + %tmp1 = load i32, i32* @i1 + ret i32 %tmp1 +} + +; NOTE: Similar to f3() but with direct TLS segment access disabled +define i32 @f18() #1 { +; X86_LINUX-LABEL: f18: +; X86_LINUX: movl i2@INDNTPOFF, %eax +; X86_LINUX-NEXT: movl %gs:0, %ecx +; X86_LINUX-NEXT: movl (%ecx,%eax), %eax +; X86_LINUX-NEXT: ret +; X64_LINUX-LABEL: f18: +; X64_LINUX: movq i2@GOTTPOFF(%rip), %rax +; X64_LINUX-NEXT: movq %fs:0, %rcx +; X64_LINUX-NEXT: movl (%rcx,%rax), %eax +; X64_LINUX-NEXT: ret +; X86_ISEL_LINUX-LABEL: f18: +; X86_ISEL_LINUX: movl i2@INDNTPOFF, %eax +; X86_ISEL_LINUX-NEXT: movl %gs:0, %ecx +; X86_ISEL_LINUX-NEXT: movl (%ecx,%eax), %eax +; X86_ISEL_LINUX-NEXT: ret +; X64_ISEL_LINUX-LABEL: f18: +; X64_ISEL_LINUX: movq i2@GOTTPOFF(%rip), %rax +; X64_ISEL_LINUX-NEXT: movq %fs:0, %rcx +; X64_ISEL_LINUX-NEXT: movl (%rcx,%rax), %eax +; X64_ISEL_LINUX-NEXT: ret + + +entry: + %tmp1 = load i32, i32* @i2 + ret i32 %tmp1 +} + +attributes #0 = { "indirect-tls-seg-refs" } +attributes #1 = { nounwind "indirect-tls-seg-refs" } -- 2.7.4