[clang] 3f40ad7 - Add ifunc support for Windows on AArch64. (#111962)

via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 14 05:45:20 PST 2024


Author: Daniel Kiss
Date: 2024-11-14T14:45:15+01:00
New Revision: 3f40ad7ba83ecf6f374039191ae7ceeb1f5fe831

URL: https://github.com/llvm/llvm-project/commit/3f40ad7ba83ecf6f374039191ae7ceeb1f5fe831
DIFF: https://github.com/llvm/llvm-project/commit/3f40ad7ba83ecf6f374039191ae7ceeb1f5fe831.diff

LOG: Add ifunc support for Windows on AArch64. (#111962)

On Windows there is no platform support for ifunc but we could lower
them to global function pointers.
This also enables FMV for Windows with Clang and Compiler-rt.

Depends on #111961

Added: 
    clang/test/CodeGen/ifunc-win.c

Modified: 
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/TargetInfo.h
    clang/test/CodeGen/attr-ifunc.c
    clang/test/CodeGen/ifunc.c
    llvm/lib/Target/AArch64/AArch64TargetMachine.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index b3c357ec906a23..6035a563d5fce7 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -477,6 +477,9 @@ def TargetELF : TargetSpec {
 def TargetELFOrMachO : TargetSpec {
   let ObjectFormats = ["ELF", "MachO"];
 }
+def TargetIFuncSupport : TargetSpec {
+  let CustomCode = [{ Target.supportsIFunc() }];
+}
 def TargetWindowsArm64EC : TargetSpec {
   let CustomCode = [{ Target.getTriple().isWindowsArm64EC() }];
 }
@@ -1855,7 +1858,7 @@ def IBOutletCollection : InheritableAttr {
   let Documentation = [Undocumented];
 }
 
-def IFunc : Attr, TargetSpecificAttr<TargetELFOrMachO> {
+def IFunc : Attr, TargetSpecificAttr<TargetIFuncSupport> {
   let Spellings = [GCC<"ifunc">];
   let Args = [StringArgument<"Resolver">];
   let Subjects = SubjectList<[Function]>;

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 8044eb80a44a72..2fdceca163ee63 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -6051,12 +6051,19 @@ declared entity. The entity must not have weak linkage; for example, in C++,
 it cannot be applied to a declaration if a definition at that location would be
 considered inline.
 
-Not all targets support this attribute. ELF target support depends on both the
-linker and runtime linker, and is available in at least lld 4.0 and later,
-binutils 2.20.1 and later, glibc v2.11.1 and later, and FreeBSD 9.1 and later.
-Mach-O targets support it, but with slightly 
diff erent semantics: the resolver
-is run at first call, instead of at load time by the runtime linker. Targets
-other than ELF and Mach-O currently do not support this attribute.
+Not all targets support this attribute:
+
+- ELF target support depends on both the linker and runtime linker, and is
+  available in at least lld 4.0 and later, binutils 2.20.1 and later, glibc
+  v2.11.1 and later, and FreeBSD 9.1 and later.
+- Mach-O targets support it, but with slightly 
diff erent semantics: the resolver
+  is run at first call, instead of at load time by the runtime linker.
+- Windows target supports it on AArch64, but with 
diff erent semantics: the
+  ``ifunc`` is replaced with a global function pointer, and the call is replaced
+  with an indirect call. The function pointer is initialized by a constructor
+  that calls the resolver.
+- Baremetal target supports it on AVR.
+- Other targets currently do not support this attribute.
   }];
 }
 

diff  --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h
index 25eda907d20a7b..2b3552854e1f9b 100644
--- a/clang/include/clang/Basic/TargetInfo.h
+++ b/clang/include/clang/Basic/TargetInfo.h
@@ -1497,6 +1497,10 @@ class TargetInfo : public TransferrableTargetInfo,
   bool supportsIFunc() const {
     if (getTriple().isOSBinFormatMachO())
       return true;
+    if (getTriple().isOSWindows() && getTriple().isAArch64())
+      return true;
+    if (getTriple().getArch() == llvm::Triple::ArchType::avr)
+      return true;
     return getTriple().isOSBinFormatELF() &&
            ((getTriple().isOSLinux() && !getTriple().isMusl()) ||
             getTriple().isOSFreeBSD());

diff  --git a/clang/test/CodeGen/attr-ifunc.c b/clang/test/CodeGen/attr-ifunc.c
index 24d66433ae090f..c9e70b17a83023 100644
--- a/clang/test/CodeGen/attr-ifunc.c
+++ b/clang/test/CodeGen/attr-ifunc.c
@@ -2,8 +2,10 @@
 // RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only -DCHECK_ALIASES %s
 // RUN: %clang_cc1 -triple x86_64-linux -verify -emit-llvm-only %s
 // RUN: %clang_cc1 -triple x86_64-apple-macosx -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -verify -emit-llvm-only %s
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvcu -verify -emit-llvm-only %s
 
-#if defined(_WIN32)
+#if defined(_WIN32) && !defined(__aarch64__)
 void foo(void) {}
 void bar(void) __attribute__((ifunc("foo")));
 // expected-warning at -1 {{unknown attribute 'ifunc' ignored}}

diff  --git a/clang/test/CodeGen/ifunc-win.c b/clang/test/CodeGen/ifunc-win.c
new file mode 100644
index 00000000000000..7c9d6f6516c70f
--- /dev/null
+++ b/clang/test/CodeGen/ifunc-win.c
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -O2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
+// RUN: %clang_cc1 -triple aarch64-pc-windows-msvc -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
+
+int foo(int) __attribute__ ((ifunc("foo_ifunc")));
+
+static int f1(int i) {
+  return i + 1;
+}
+
+static int f2(int i) {
+  return i + 2;
+}
+
+typedef int (*foo_t)(int);
+
+volatile int global;
+
+static foo_t foo_ifunc(void) {
+  return global ? f1 : f2;
+}
+
+int bar(void) {
+  return foo(1);
+}
+
+extern void goo(void);
+
+void bar2(void) {
+  goo();
+}
+
+extern void goo(void) __attribute__ ((ifunc("goo_ifunc")));
+
+void* goo_ifunc(void) {
+  return 0;
+}
+
+/// The ifunc is emitted after its resolver.
+void *hoo_ifunc(void) { return 0; }
+extern void hoo(int) __attribute__ ((ifunc("hoo_ifunc")));
+
+/// ifunc on Windows is lowered to global pointers and an indirect call.
+// CHECK: @global = dso_local global i32 0, align 4
+// CHECK: {{.*}} = internal{{.*}}global{{.*}}poison, align 8
+/// Register the constructor for initialisation.
+// CHECK: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 10, ptr @{{.*}}, ptr null }]
+
+// CHECK-LABEL: @bar()
+// CHECK   %0 = load ptr, ptr @0, align 8
+// CHECK   %call = call i32 %0(i32 noundef 1)
+
+// CHECK-LABEL: @bar2()
+// CHECK %0 = load ptr, ptr getelementptr inbounds ([3 x ptr], ptr @0, i32 0, i32 1), align 8
+// CHECK call void %0()
+
+// CHECK: define internal void @{{.*}}()
+
+// SAN: define {{(dso_local )?}}noalias {{(noundef )?}}ptr @goo_ifunc() {{(local_unnamed_addr )?}}
+
+// SAN: define {{(dso_local )?}}noalias {{(noundef )?}}ptr @hoo_ifunc() {{(local_unnamed_addr )?}}
+
+// SAN: define internal {{(fastcc )?}}{{(noundef )?}}nonnull ptr @foo_ifunc() {{(unnamed_addr )?}}
+

diff  --git a/clang/test/CodeGen/ifunc.c b/clang/test/CodeGen/ifunc.c
index 2849246f93dc3b..7d21f742e86765 100644
--- a/clang/test/CodeGen/ifunc.c
+++ b/clang/test/CodeGen/ifunc.c
@@ -12,6 +12,11 @@
 // RUN: %clang_cc1 -triple arm64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
 // RUN: %clang_cc1 -triple x86_64-apple-macosx -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
 // RUN: %clang_cc1 -triple avr-unknown-unknown -emit-llvm -o - %s | FileCheck %s --check-prefix=AVR
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -O2 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=thread -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -fsanitize=address -O2 -emit-llvm -o - %s | FileCheck %s --check-prefix=SAN
+
 
 /// The ifunc is emitted before its resolver.
 int foo(int) __attribute__ ((ifunc("foo_ifunc")));

diff  --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index e0e559b457f6d6..c588f2ccf42f02 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -49,6 +49,7 @@
 #include "llvm/TargetParser/Triple.h"
 #include "llvm/Transforms/CFGuard.h"
 #include "llvm/Transforms/Scalar.h"
+#include "llvm/Transforms/Utils/LowerIFunc.h"
 #include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
 #include <memory>
 #include <optional>
@@ -570,6 +571,11 @@ void AArch64TargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
       [=](LoopPassManager &LPM, OptimizationLevel Level) {
         LPM.addPass(LoopIdiomVectorizePass());
       });
+  if (getTargetTriple().isOSWindows())
+    PB.registerPipelineEarlySimplificationEPCallback(
+        [](ModulePassManager &PM, OptimizationLevel, ThinOrFullLTOPhase) {
+          PM.addPass(LowerIFuncPass());
+        });
 }
 
 TargetTransformInfo


        


More information about the cfe-commits mailing list