From: scott.k.mitch1@gmail.com
To: dev@dpdk.org
Cc: mb@smartsharesystems.com, stephen@networkplumber.org,
bruce.richardson@intel.com,
Scott Mitchell <scott.k.mitch1@gmail.com>
Subject: [PATCH v9] eal: RTE_PTR_ADD/SUB char* for compiler optimizations
Date: Sat, 17 Jan 2026 13:03:22 -0800 [thread overview]
Message-ID: <20260117210322.5419-1-scott.k.mitch1@gmail.com> (raw)
In-Reply-To: <20260116231907.13895-1-scott.k.mitch1@gmail.com>
From: Scott Mitchell <scott.k.mitch1@gmail.com>
Modify RTE_PTR_ADD and RTE_PTR_SUB to use char* pointer arithmetic
on Clang instead of uintptr_t casts. Benefits of this approach:
- API compatibility: works for both integer and pointer inputs
- Retains simple macros: no pragmas, no _Generic
- Enables Clang optimizations: Clang can now unroll and vectorize
pointer loops. GCC uses uintptr_t to avoid false positive warnings.
Example use case which benefits is __rte_raw_cksum. Performance
results from cksum_perf_autotest on Intel Xeon (Cascade Lake,
AVX-512) built with Clang 18.1 (TSC cycles/byte):
Block size Before After Improvement
100 0.40 0.24 ~40%
1500 0.50 0.06 ~8x
9000 0.49 0.06 ~8x
Signed-off-by: Scott Mitchell <scott.k.mitch1@gmail.com>
---
v9:
- Fix include order: system includes, then DPDK includes, then application includes
- Use NOHUGE_OK and ASAN_OK constants in REGISTER_FAST_TEST (instead of true, true)
v8:
- Remove tests for types < 32-bit (bool, char, short, uint8_t, uint16_t)
- Merge test_ptr_add_sub_typedefs() into test_ptr_add_sub_integer_types()
- Separate RTE_PTR_ADD and RTE_PTR_SUB documentation
- Move Clang/GCC implementation note from Doxygen to regular comment
- Tests verify both intermediate ADD result and SUB round-trip
- Use uintptr_t cast consistently for all integer-to-pointer conversions
- Make TEST_RETVAL calculated from TEST_INITVAL + TEST_INCREMENT
v7:
- Fix tests: use TEST_BUFFER_SIZE macro for buffer allocation
- Fix tests: ADD then SUB same amount to avoid out-of-bounds pointer arithmetic
- All RTE_PTR_SUB tests now verify round-trip (ADD+SUB returns to original)
v6:
- Make char* optimization Clang-only to avoid GCC false positive warnings
- Improve tests: use named constants instead of magic numbers
- Improve tests: use void* casts on expected values instead of uintptr_t on results
v5:
- Initial implementation with char* arithmetic for all compilers
v4:
- Used _Generic for type-based dispatch with char* casts
- Had warnings on both Clang and GCC due to _Generic type-checking all branches
---
app/test/meson.build | 1 +
app/test/test_ptr_add_sub.c | 194 +++++++++++++++++++++++++++++++++++
lib/eal/include/rte_common.h | 15 ++-
3 files changed, 209 insertions(+), 1 deletion(-)
create mode 100644 app/test/test_ptr_add_sub.c
diff --git a/app/test/meson.build b/app/test/meson.build
index efec42a6bf..80a19d65ba 100644
--- a/app/test/meson.build
+++ b/app/test/meson.build
@@ -152,6 +152,7 @@ source_file_deps = {
'test_power_intel_uncore.c': ['power', 'power_intel_uncore'],
'test_power_kvm_vm.c': ['power', 'power_kvm_vm'],
'test_prefetch.c': [],
+ 'test_ptr_add_sub.c': [],
'test_ptr_compress.c': ['ptr_compress'],
'test_rand_perf.c': [],
'test_rawdev.c': ['rawdev', 'bus_vdev', 'raw_skeleton'],
diff --git a/app/test/test_ptr_add_sub.c b/app/test/test_ptr_add_sub.c
new file mode 100644
index 0000000000..5646d188ce
--- /dev/null
+++ b/app/test/test_ptr_add_sub.c
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2026 Apple Inc.
+ */
+
+#include <stdint.h>
+
+#include <rte_common.h>
+
+#include "test.h"
+
+/* Test constants for 32-bit and 64-bit integer types */
+#define TEST_INITVAL 0x1000
+#define TEST_INCREMENT 100
+#define TEST_RETVAL ((void *)(TEST_INITVAL + TEST_INCREMENT))
+
+/* Buffer size for pointer tests */
+#define TEST_BUFFER_SIZE (TEST_INCREMENT + 256)
+
+/* Test 32-bit and 64-bit integer types */
+static int
+test_ptr_add_sub_integer_types(void)
+{
+ void *result;
+
+ unsigned long long ull = TEST_INITVAL;
+ result = RTE_PTR_ADD(ull, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ull,
+ "RTE_PTR_SUB round-trip failed for unsigned long long");
+
+ long long ll = TEST_INITVAL;
+ result = RTE_PTR_ADD(ll, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ll,
+ "RTE_PTR_SUB round-trip failed for long long");
+
+ unsigned long ul = TEST_INITVAL;
+ result = RTE_PTR_ADD(ul, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ul,
+ "RTE_PTR_SUB round-trip failed for unsigned long");
+
+ long l = TEST_INITVAL;
+ result = RTE_PTR_ADD(l, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for long");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)l,
+ "RTE_PTR_SUB round-trip failed for long");
+
+ unsigned int ui = TEST_INITVAL;
+ result = RTE_PTR_ADD(ui, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for unsigned int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)ui,
+ "RTE_PTR_SUB round-trip failed for unsigned int");
+
+ int i = TEST_INITVAL;
+ result = RTE_PTR_ADD(i, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for int");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)i,
+ "RTE_PTR_SUB round-trip failed for int");
+
+ uint64_t u64 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u64, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint64_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u64,
+ "RTE_PTR_SUB round-trip failed for uint64_t");
+
+ uint32_t u32 = TEST_INITVAL;
+ result = RTE_PTR_ADD(u32, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uint32_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(uintptr_t)u32,
+ "RTE_PTR_SUB round-trip failed for uint32_t");
+
+ uintptr_t uptr = TEST_INITVAL;
+ result = RTE_PTR_ADD(uptr, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for uintptr_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)uptr,
+ "RTE_PTR_SUB round-trip failed for uintptr_t");
+
+ size_t sz = TEST_INITVAL;
+ result = RTE_PTR_ADD(sz, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, TEST_RETVAL,
+ "RTE_PTR_ADD failed for size_t");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)sz,
+ "RTE_PTR_SUB round-trip failed for size_t");
+
+ return 0;
+}
+
+/* Test pointer types including const correctness */
+static int
+test_ptr_add_sub_pointer_types(void)
+{
+ char buffer[TEST_BUFFER_SIZE];
+ void *result;
+
+ /* Test void* and const void* */
+ void *vp = buffer;
+ result = RTE_PTR_ADD(vp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, vp,
+ "RTE_PTR_SUB round-trip failed for void*");
+
+ const void *cvp = buffer;
+ result = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const void*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cvp,
+ "RTE_PTR_SUB round-trip failed for const void*");
+
+ /* Test char* and const char* */
+ char *cp = buffer;
+ result = RTE_PTR_ADD(cp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)cp,
+ "RTE_PTR_SUB round-trip failed for char*");
+
+ const char *ccp = buffer;
+ result = RTE_PTR_ADD(ccp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const char*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)ccp,
+ "RTE_PTR_SUB round-trip failed for const char*");
+
+ /* Test uint32_t* and const uint32_t* */
+ uint32_t *u32p = (uint32_t *)buffer;
+ result = RTE_PTR_ADD(u32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)u32p,
+ "RTE_PTR_SUB round-trip failed for uint32_t*");
+
+ const uint32_t *cu32p = (const uint32_t *)buffer;
+ result = RTE_PTR_ADD(cu32p, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed for const uint32_t*");
+ result = RTE_PTR_SUB(result, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result, (const void *)cu32p,
+ "RTE_PTR_SUB round-trip failed for const uint32_t*");
+
+ /* Verify assigning to const pointer works (adding const is safe) */
+ const void *result_const = RTE_PTR_ADD(cvp, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, (const void *)(buffer + TEST_INCREMENT),
+ "RTE_PTR_ADD failed when assigning to const void*");
+ result_const = RTE_PTR_SUB(result_const, TEST_INCREMENT);
+ TEST_ASSERT_EQUAL(result_const, cvp,
+ "RTE_PTR_SUB round-trip failed when assigning to const void*");
+
+ return 0;
+}
+
+/* Main test function that runs all subtests */
+static int
+test_ptr_add_sub(void)
+{
+ int ret;
+
+ ret = test_ptr_add_sub_integer_types();
+ if (ret != 0)
+ return ret;
+
+ ret = test_ptr_add_sub_pointer_types();
+ if (ret != 0)
+ return ret;
+
+ return 0;
+}
+
+REGISTER_FAST_TEST(ptr_add_sub_autotest, NOHUGE_OK, ASAN_OK, test_ptr_add_sub);
diff --git a/lib/eal/include/rte_common.h b/lib/eal/include/rte_common.h
index 9e7d84f929..f2935929f7 100644
--- a/lib/eal/include/rte_common.h
+++ b/lib/eal/include/rte_common.h
@@ -551,12 +551,25 @@ static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
/**
* add a byte-value offset to a pointer
*/
-#define RTE_PTR_ADD(ptr, x) ((void*)((uintptr_t)(ptr) + (x)))
+#ifdef RTE_CC_CLANG
+/*
+ * Clang doesn't optimize through uintptr_t, (char*) enables
+ * optimizations and doesn't generate warnings. GCC does optimize
+ * through uintptr_t but throws warnings (e.g. array-bounds) when cast to char*.
+ */
+#define RTE_PTR_ADD(ptr, x) ((void *)((char *)(uintptr_t)(ptr) + (x)))
+#else
+#define RTE_PTR_ADD(ptr, x) ((void *)((uintptr_t)(ptr) + (x)))
+#endif
/**
* subtract a byte-value offset from a pointer
*/
+#ifdef RTE_CC_CLANG
+#define RTE_PTR_SUB(ptr, x) ((void *)((char *)(uintptr_t)(ptr) - (x)))
+#else
#define RTE_PTR_SUB(ptr, x) ((void *)((uintptr_t)(ptr) - (x)))
+#endif
/**
* get the difference between two pointer values, i.e. how far apart
--
2.39.5 (Apple Git-154)
next prev parent reply other threads:[~2026-01-17 21:03 UTC|newest]
Thread overview: 60+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-14 16:07 [PATCH v6] eal: RTE_PTR_ADD/SUB char* for compiler optimizations scott.k.mitch1
2026-01-14 21:56 ` [PATCH v7] " scott.k.mitch1
2026-01-16 11:39 ` Morten Brørup
2026-01-16 22:38 ` Scott Mitchell
2026-01-16 23:19 ` [PATCH v8] " scott.k.mitch1
2026-01-17 2:44 ` Stephen Hemminger
2026-01-17 21:07 ` Scott Mitchell
2026-01-17 21:03 ` scott.k.mitch1 [this message]
2026-01-18 6:12 ` [PATCH v9] " Stephen Hemminger
2026-01-23 16:20 ` Scott Mitchell
2026-01-20 12:59 ` Morten Brørup
2026-01-23 16:27 ` [PATCH v10] " scott.k.mitch1
2026-01-24 7:58 ` Morten Brørup
2026-01-24 8:59 ` Scott Mitchell
2026-01-24 22:59 ` Scott Mitchell
2026-01-24 9:11 ` [PATCH v11] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-25 11:11 ` scott.k.mitch1
2026-01-25 11:12 ` [PATCH v12] " scott.k.mitch1
2026-01-25 19:36 ` [REVIEW] " Stephen Hemminger
2026-01-25 22:24 ` Scott Mitchell
2026-01-26 8:19 ` Morten Brørup
2026-01-25 22:30 ` [PATCH v13] " scott.k.mitch1
2026-01-26 8:03 ` [PATCH v14] " scott.k.mitch1
2026-01-26 14:35 ` Morten Brørup
2026-01-26 21:29 ` Scott Mitchell
2026-01-27 5:11 ` Scott Mitchell
2026-01-27 2:02 ` [PATCH v15 0/2] " scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 2:02 ` [PATCH v15 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 0/2] " scott.k.mitch1
2026-01-27 5:28 ` [PATCH v16 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-01-27 11:16 ` Mattias Rönnblom
2026-01-27 14:07 ` Stephen Hemminger
2026-01-27 5:29 ` [PATCH v16 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 0/2] " scott.k.mitch1
2026-02-02 5:24 ` [PATCH v17 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-03 8:24 ` Morten Brørup
2026-02-03 9:48 ` David Marchand
2026-02-02 5:24 ` [PATCH v17 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-03 9:08 ` Morten Brørup
2026-02-03 16:24 ` Scott Mitchell
2026-02-03 9:51 ` David Marchand
2026-02-03 16:25 ` Scott Mitchell
2026-02-03 21:18 ` [PATCH v18 0/2] " scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 1/2] eal: remove alloc_size from rte_lcore_var_alloc scott.k.mitch1
2026-02-03 21:18 ` [PATCH v18 2/2] eal: RTE_PTR_ADD/SUB API improvements scott.k.mitch1
2026-02-04 2:46 ` [PATCH v19] " scott.k.mitch1
2026-02-04 5:20 ` Scott Mitchell
2026-02-04 6:12 ` [PATCH v20] " scott.k.mitch1
2026-02-04 22:47 ` Morten Brørup
2026-02-05 6:53 ` Scott Mitchell
2026-02-05 7:03 ` [PATCH v21] " scott.k.mitch1
2026-02-05 7:50 ` Morten Brørup
2026-02-06 1:04 ` Scott Mitchell
2026-02-06 1:01 ` [PATCH v22] " scott.k.mitch1
2026-02-06 4:28 ` [PATCH v23] " scott.k.mitch1
2026-02-06 16:09 ` Stephen Hemminger
2026-02-07 1:45 ` [PATCH v24] " scott.k.mitch1
2026-01-27 20:28 ` [REVIEW] " Stephen Hemminger
2026-02-02 5:17 ` Scott Mitchell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260117210322.5419-1-scott.k.mitch1@gmail.com \
--to=scott.k.mitch1@gmail.com \
--cc=bruce.richardson@intel.com \
--cc=dev@dpdk.org \
--cc=mb@smartsharesystems.com \
--cc=stephen@networkplumber.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox