[llvm] [orc-rt] Add C addressing regression tests for functions. (PR #227518)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 29 16:53:22 PDT 2026


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/227518

Add tests that check that JIT'd C code can call functions, both in the same object and in other objects: direct calls, calls through function pointers stored in initialized data, and tail calls. The tail call tests only run at -O2, since an unoptimized build may not emit tail calls.

>From f796c4062d593bee328f3714fbf823ebc353a857 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Wed, 30 Sep 2026 08:47:04 +1000
Subject: [PATCH] [orc-rt] Add C addressing regression tests for functions.

Add tests that check that JIT'd C code can call functions, both in the same
object and in other objects: direct calls, calls through function pointers
stored in initialized data, and tail calls. The tail call tests only run at
-O2, since an unoptimized build may not emit tail calls.
---
 .../cross-object/global-function-call.test    | 26 +++++++++++++++
 .../global-function-pointer-in-data.test      | 28 ++++++++++++++++
 .../global-function-tail-call.test            | 32 +++++++++++++++++++
 .../cross-object/hidden-function-call.test    | 27 ++++++++++++++++
 .../same-object/global-function-call.c        | 22 +++++++++++++
 .../global-function-pointer-in-data.c         | 24 ++++++++++++++
 .../same-object/static-function-call.c        | 22 +++++++++++++
 .../same-object/static-function-tail-call.c   | 30 +++++++++++++++++
 8 files changed, 211 insertions(+)
 create mode 100644 orc-rt/test/regression/languages/c/addressing/cross-object/global-function-call.test
 create mode 100644 orc-rt/test/regression/languages/c/addressing/cross-object/global-function-pointer-in-data.test
 create mode 100644 orc-rt/test/regression/languages/c/addressing/cross-object/global-function-tail-call.test
 create mode 100644 orc-rt/test/regression/languages/c/addressing/cross-object/hidden-function-call.test
 create mode 100644 orc-rt/test/regression/languages/c/addressing/same-object/global-function-call.c
 create mode 100644 orc-rt/test/regression/languages/c/addressing/same-object/global-function-pointer-in-data.c
 create mode 100644 orc-rt/test/regression/languages/c/addressing/same-object/static-function-call.c
 create mode 100644 orc-rt/test/regression/languages/c/addressing/same-object/static-function-tail-call.c

diff --git a/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-call.test b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-call.test
new file mode 100644
index 0000000000000..1b7f44772266b
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-call.test
@@ -0,0 +1,26 @@
+# Check that JIT'd code can call a global function defined in another object.
+#
+# Stresses: fixups for calls to functions defined in another object, which the
+# JIT linker may route through a stub.
+
+RUN: rm -rf %t && split-file %s %t
+RUN: %{cc} -O0 -c -o %t/def.O0.o %t/def.c
+RUN: %{cc} -O0 -c -o %t/main.O0.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O0.o %t/def.O0.o | FileCheck %s
+RUN: %{cc} -O2 -c -o %t/def.O2.o %t/def.c
+RUN: %{cc} -O2 -c -o %t/main.O2.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O2.o %t/def.O2.o | FileCheck %s
+
+CHECK: JIT result: 0
+
+#--- def.c
+int addOne(int X) { return X + 1; }
+
+#--- main.c
+int addOne(int X);
+
+int main(void) {
+  if (addOne(41) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-pointer-in-data.test b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-pointer-in-data.test
new file mode 100644
index 0000000000000..d3772a89c5569
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-pointer-in-data.test
@@ -0,0 +1,28 @@
+# Check that a pointer to a global function defined in another object, stored
+# in initialized data, can be called.
+#
+# Stresses: fixups for pointers stored in data, targeting functions defined in
+# another object.
+
+RUN: rm -rf %t && split-file %s %t
+RUN: %{cc} -O0 -c -o %t/def.O0.o %t/def.c
+RUN: %{cc} -O0 -c -o %t/main.O0.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O0.o %t/def.O0.o | FileCheck %s
+RUN: %{cc} -O2 -c -o %t/def.O2.o %t/def.c
+RUN: %{cc} -O2 -c -o %t/main.O2.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O2.o %t/def.O2.o | FileCheck %s
+
+CHECK: JIT result: 0
+
+#--- def.c
+int addOne(int X) { return X + 1; }
+
+#--- main.c
+int addOne(int X);
+int (*AddOnePtr)(int) = addOne;
+
+int main(void) {
+  if (AddOnePtr(41) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-tail-call.test b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-tail-call.test
new file mode 100644
index 0000000000000..91cdcbfe1e0bb
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/cross-object/global-function-tail-call.test
@@ -0,0 +1,32 @@
+# Check that JIT'd code can tail-call a global function defined in another
+# object.
+#
+# Stresses: fixups for tail calls (branches rather than calls) to functions
+# defined in another object, which the JIT linker may route through a stub.
+#
+# Only runs at -O2: an unoptimized build may not emit tail calls.
+
+RUN: rm -rf %t && split-file %s %t
+RUN: %{cc} -O2 -c -o %t/def.o %t/def.c
+RUN: %{cc} -O2 -c -o %t/main.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.o %t/def.o | FileCheck %s
+
+CHECK: JIT result: 0
+
+#--- def.c
+int addOne(int X) { return X + 1; }
+
+#--- main.c
+int addOne(int X);
+
+// noinline, to prevent inlining into main, where the tail call would become a
+// plain call.
+__attribute__((noinline)) static int tailCallAddOne(int X) {
+  return addOne(X);
+}
+
+int main(void) {
+  if (tailCallAddOne(41) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/cross-object/hidden-function-call.test b/orc-rt/test/regression/languages/c/addressing/cross-object/hidden-function-call.test
new file mode 100644
index 0000000000000..15b874ddbb119
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/cross-object/hidden-function-call.test
@@ -0,0 +1,27 @@
+# Check that JIT'd code can call a hidden function defined in another object.
+#
+# Stresses: fixups for calls to functions defined in another object. Hidden
+# functions must be defined in the same linkage unit, so the compiler may call
+# them directly rather than through a PLT, where the object format has one.
+
+RUN: rm -rf %t && split-file %s %t
+RUN: %{cc} -O0 -c -o %t/def.O0.o %t/def.c
+RUN: %{cc} -O0 -c -o %t/main.O0.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O0.o %t/def.O0.o | FileCheck %s
+RUN: %{cc} -O2 -c -o %t/def.O2.o %t/def.c
+RUN: %{cc} -O2 -c -o %t/main.O2.o %t/main.c
+RUN: %{obj-jit} -show-jit-result %t/main.O2.o %t/def.O2.o | FileCheck %s
+
+CHECK: JIT result: 0
+
+#--- def.c
+__attribute__((visibility("hidden"))) int addOne(int X) { return X + 1; }
+
+#--- main.c
+__attribute__((visibility("hidden"))) int addOne(int X);
+
+int main(void) {
+  if (addOne(41) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/same-object/global-function-call.c b/orc-rt/test/regression/languages/c/addressing/same-object/global-function-call.c
new file mode 100644
index 0000000000000..3b62d58bcb1c0
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/same-object/global-function-call.c
@@ -0,0 +1,22 @@
+// Check that JIT'd code can call a global function defined in the same object.
+//
+// Stresses: fixups for calls to functions in the same object.
+//
+// RUN: %{cc} -O0 -c -o %t.O0.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O0.o | FileCheck %s
+// RUN: %{cc} -O2 -c -o %t.O2.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O2.o | FileCheck %s
+
+// CHECK: JIT result: 0
+
+// noinline, to prevent inlining.
+__attribute__((noinline)) int addOne(int X) { return X + 1; }
+
+// Non-const global argument, to prevent interprocedural constant propagation.
+int Arg = 41;
+
+int main(void) {
+  if (addOne(Arg) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/same-object/global-function-pointer-in-data.c b/orc-rt/test/regression/languages/c/addressing/same-object/global-function-pointer-in-data.c
new file mode 100644
index 0000000000000..5660f376c3e42
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/same-object/global-function-pointer-in-data.c
@@ -0,0 +1,24 @@
+// Check that a pointer to a global function, stored in initialized data in the
+// same object, can be called.
+//
+// Stresses: fixups for pointers stored in data, targeting functions in the
+// same object.
+//
+// RUN: %{cc} -O0 -c -o %t.O0.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O0.o | FileCheck %s
+// RUN: %{cc} -O2 -c -o %t.O2.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O2.o | FileCheck %s
+
+// CHECK: JIT result: 0
+
+int addOne(int X) { return X + 1; }
+
+// No barrier needed: a non-const global's value can't be propagated, so the
+// call through AddOnePtr can't be devirtualized.
+int (*AddOnePtr)(int) = addOne;
+
+int main(void) {
+  if (AddOnePtr(41) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/same-object/static-function-call.c b/orc-rt/test/regression/languages/c/addressing/same-object/static-function-call.c
new file mode 100644
index 0000000000000..e68b784cc1449
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/same-object/static-function-call.c
@@ -0,0 +1,22 @@
+// Check that JIT'd code can call a static function defined in the same object.
+//
+// Stresses: fixups for calls to functions in the same object.
+//
+// RUN: %{cc} -O0 -c -o %t.O0.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O0.o | FileCheck %s
+// RUN: %{cc} -O2 -c -o %t.O2.o %s
+// RUN: %{obj-jit} -show-jit-result %t.O2.o | FileCheck %s
+
+// CHECK: JIT result: 0
+
+// noinline, to prevent inlining.
+__attribute__((noinline)) static int addOne(int X) { return X + 1; }
+
+// Non-const global argument, to prevent interprocedural constant propagation.
+int Arg = 41;
+
+int main(void) {
+  if (addOne(Arg) != 42)
+    return 1;
+  return 0;
+}
diff --git a/orc-rt/test/regression/languages/c/addressing/same-object/static-function-tail-call.c b/orc-rt/test/regression/languages/c/addressing/same-object/static-function-tail-call.c
new file mode 100644
index 0000000000000..2c8cdf4938996
--- /dev/null
+++ b/orc-rt/test/regression/languages/c/addressing/same-object/static-function-tail-call.c
@@ -0,0 +1,30 @@
+// Check that JIT'd code can tail-call a static function defined in the same
+// object.
+//
+// Stresses: fixups for tail calls (branches rather than calls) to functions in
+// the same object.
+//
+// Only runs at -O2: an unoptimized build may not emit tail calls.
+//
+// RUN: %{cc} -O2 -c -o %t.o %s
+// RUN: %{obj-jit} -show-jit-result %t.o | FileCheck %s
+
+// CHECK: JIT result: 0
+
+// noinline, to prevent inlining.
+__attribute__((noinline)) static int addOne(int X) { return X + 1; }
+
+// noinline, to prevent inlining into main, where the tail call would become a
+// plain call.
+__attribute__((noinline)) static int tailCallAddOne(int X) {
+  return addOne(X);
+}
+
+// Non-const global argument, to prevent interprocedural constant propagation.
+int Arg = 41;
+
+int main(void) {
+  if (tailCallAddOne(Arg) != 42)
+    return 1;
+  return 0;
+}



More information about the llvm-commits mailing list