master: x86-64, struct-by-value: coordinate arglist transforms
stassats via Sbcl-commits <[email protected]>
| Newsgroups | gmane.lisp.steel-bank.cvs |
|---|---|
| Message-ID | <[email protected]> |
The branch "master" has been updated in SBCL:
via 6a39892471ffe36d723cd07928bff3182bfd8ac5 (commit)
from 6fff197f3513ef36f05bb919bd1861947434bdf8 (commit)
- Log -----------------------------------------------------------------
commit 6a39892471ffe36d723cd07928bff3182bfd8ac5
Author: Jesse Bouwman <[email protected]>
Date: Mon Apr 27 14:05:06 2026 -0700
x86-64, struct-by-value: coordinate arglist transforms
---
src/compiler/x86-64/c-call.lisp | 6 ++++++
tests/alien-struct-by-value.c | 15 +++++++++++++++
tests/alien-struct-by-value.impure.lisp | 19 +++++++++++++++++++
3 files changed, 40 insertions(+)
diff --git a/src/compiler/x86-64/c-call.lisp b/src/compiler/x86-64/c-call.lisp
index 7d20f433d..ef603ab17 100644
--- a/src/compiler/x86-64/c-call.lisp
+++ b/src/compiler/x86-64/c-call.lisp
@@ -520,6 +520,12 @@ Floats are passed in integer registers."
(and (alien-integer-type-p result-type)
(> (sb-alien::alien-integer-type-bits result-type) 64)))
(collect ((new-args) (lambda-vars) (new-arg-types))
+ ;; When the OUTER struct-return path injected a hidden
+ ;; buffer SAP as the first arg, thread it through.
+ (let ((buf-var (and large-struct-return-p (gensym "BUF"))))
+ (when buf-var
+ (lambda-vars buf-var)
+ (new-args buf-var)))
(dolist (type arg-types)
(let ((arg (gensym)))
(lambda-vars arg)
diff --git a/tests/alien-struct-by-value.c b/tests/alien-struct-by-value.c
index a77cd7136..28f4de700 100644
--- a/tests/alien-struct-by-value.c
+++ b/tests/alien-struct-by-value.c
@@ -427,3 +427,18 @@ struct nest_di nest_di_make(double d, int i) {
struct nest_di s; s.inner.d = d; s.inner.i = i; return s;
}
double nest_di_sum(struct nest_di s) { return s.inner.d + (double)s.inner.i; }
+
+/*
+ * Large struct return + __int128 argument. Exercise interaction of
+ * hidden sret pointer (injected by the struct-return IR1 transform)
+ * and int128 splitting (rewrites the arg list): these must agree on
+ * whether the buffer arg is present.
+ */
+struct three_u64 { unsigned long long a, b, c; };
+struct three_u64 three_u64_from_u128(__uint128_t x) {
+ struct three_u64 s;
+ s.a = (unsigned long long) x;
+ s.b = (unsigned long long) (x >> 64);
+ s.c = s.a ^ s.b;
+ return s;
+}
diff --git a/tests/alien-struct-by-value.impure.lisp b/tests/alien-struct-by-value.impure.lisp
index c845d43e2..ae685f940 100644
--- a/tests/alien-struct-by-value.impure.lisp
+++ b/tests/alien-struct-by-value.impure.lisp
@@ -786,3 +786,22 @@
(assert (= (slot (slot s 'inner) 'd) 3.5d0))
(assert (= (slot (slot s 'inner) 'i) 7))
(assert (= (nest-di-sum s) 10.5d0))))
+
+;;; Large struct return combined with an __int128 argument: the
+;;; struct-return IR1 transform injects a hidden sret-pointer arg
+;;; ahead of the original args; the int128-splitting transform
+;;; rewrites the arg list.
+#+x86-64
+(with-test (:name :struct-by-value-large-return-with-int128-arg)
+ (define-alien-routine three-u64-from-u128 (struct nil
+ (a (unsigned 64))
+ (b (unsigned 64))
+ (c (unsigned 64)))
+ (x (unsigned 128)))
+ (let* ((low #x0123456789abcdef)
+ (high #xfedcba9876543210)
+ (x (logior low (ash high 64)))
+ (s (three-u64-from-u128 x)))
+ (assert (= (slot s 'a) low))
+ (assert (= (slot s 'b) high))
+ (assert (= (slot s 'c) (logxor low high)))))
-----------------------------------------------------------------------
hooks/post-receive
--
SBCL