guix_mirror_bot pushed a commit to branch next-master
in repository guix.

commit 6bb73a58d96e78ef14e3aaa28b4efd1d6fd02698
Author: Ludovic Courtès <[email protected]>
AuthorDate: Tue Jan 13 09:38:38 2026 +0100

    transformations: Add ‘--amd-gpu’ transformation option.
    
    * guix/transformations.scm (split-on-commas): New procedure, moved from…
    (transform-package-toolchain): … here.
    (package-amd-gpu-specialization, transform-package-amd-gpu-targets): New
    procedures.
    (%transformations, %options): Add ‘amd-gpu’.
    * tests/transformations.scm ("options->transformations, amd-gpu")
    ("options->transformations, amd-gpu, not applicable")
    ("options->transformations, amd-gpu, missing clang-rocm input")
    ("options->transformations, amd-gpu, wrong GPU"): New tests.
    * doc/guix.texi (Package Transformation Options): Document it.
    
    Change-Id: I56bf0dffbf12bc08cf6318fe56952473b395c303
    Signed-off-by: Ludovic Courtès <[email protected]>
    Merges: #5583
---
 doc/guix.texi             |  33 ++++++++++++++-
 guix/transformations.scm  | 105 ++++++++++++++++++++++++++++++++++++++++++++--
 tests/transformations.scm |  41 +++++++++++++++++-
 3 files changed, 173 insertions(+), 6 deletions(-)

diff --git a/doc/guix.texi b/doc/guix.texi
index 8022655c81..7c800db83b 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -22,7 +22,7 @@
 @set SUBSTITUTE-URLS https://@value{SUBSTITUTE-SERVER-1} 
https://@value{SUBSTITUTE-SERVER-2}
 
 @copying
-Copyright @copyright{} 2012--2025 Ludovic Courtès@*
+Copyright @copyright{} 2012--2026 Ludovic Courtès@*
 Copyright @copyright{} 2013, 2014, 2016, 2024 Andreas Enge@*
 Copyright @copyright{} 2013 Nikita Karetnikov@*
 Copyright @copyright{} 2014, 2015, 2016 Alex Kost@*
@@ -13662,6 +13662,37 @@ coarse-grain counterpart of @dfn{function 
multi-versioning} as
 implemented by the GNU tool chain (@pxref{Function Multiversioning,,,
 gcc, Using the GNU Compiler Collection (GCC)}).
 
+@cindex GPUs, AMD compilation targets
+@cindex AMD GPUs
+@cindex ROCm/HIP GPU targets
+@vindex amd-gpu-targets
+@anchor{amd-gpu-transformation-option}
+@item --amd-gpu=@var{targets}
+Build relevant packages for the AMD GPUs specified by @var{targets}.
+Only packages with an @code{amd-gpu-targets} property are affected.
+@var{targets} must be a comma-separated list of
+@uref{https://llvm.org/docs/AMDGPUUsage.html#amdgpu-processor-table, AMD
+GPU target identifiers}.  For example, the command below builds the GPU
+code of @code{rocm-bandwidth-test} for AMD Instinct MI250
+(@code{gfx90a}) and for AMD Instinct MI300 (@code{gfx942}):
+
+@example
+guix build --amd-gpu=gfx90a,gfx942 rocm-bandwidth-test
+@end example
+
+To know the identifier(s) of the GPU(s) available on your machine, run:
+
+@example
+guix shell rocminfo -- rocm_agent_enumerator
+@end example
+
+Under the hood, these GPU identifiers are
+passed to Clang's @option{--offload-arch} option.
+
+When @option{--amd-gpu} is omitted, packages are built for a default set
+of GPUs, that we hope covers common needs.  Building for more GPUs
+increases build time significantly and leads to bigger package binaries.
+
 @item --with-source=@var{source}
 @itemx --with-source=@var{package}=@var{source}
 @itemx --with-source=@var{package}@@@var{version}=@var{source}
diff --git a/guix/transformations.scm b/guix/transformations.scm
index 198b55ed23..0cad18ba6e 100644
--- a/guix/transformations.scm
+++ b/guix/transformations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016-2024 Ludovic Courtès <[email protected]>
+;;; Copyright © 2016-2024, 2026 Ludovic Courtès <[email protected]>
 ;;; Copyright © 2021 Marius Bakke <[email protected]>
 ;;; Copyright © 2023 Sarthak Shah <[email protected]>
 ;;; Copyright © 2023-2025 Efraim Flashner <[email protected]>
@@ -422,15 +422,15 @@ TOOLCHAIN must be an input list."
                             (not (memq p set))))
                       #:deep? #t))))
 
+(define split-on-commas
+  (cute string-tokenize <> (char-set-complement (char-set #\,))))
+
 (define (transform-package-toolchain replacement-specs)
   "Return a procedure that, when passed a package, changes its toolchain or
 that of its dependencies according to REPLACEMENT-SPECS.  REPLACEMENT-SPECS is
 a list of strings like \"fftw=gcc-toolchain@10\" meaning that the package to
 the left of the equal sign must be built with the toolchain to the right of
 the equal sign."
-  (define split-on-commas
-    (cute string-tokenize <> (char-set-complement (char-set #\,))))
-
   (define (specification->input spec)
     (let ((package (specification->package spec)))
       (list (package-name package) package)))
@@ -704,6 +704,97 @@ for MICRO-ARCHITECTURE, a string suitable for GCC's 
'-march'."
              (rewrite obj)
              obj))))))
 
+(define (package-for-amd-gpu-targets p targets)
+  "Return a variant of P compiled for TARGETS, a list of strings denoting AMD
+GPU targets."
+  (package/inherit p
+    (properties
+     `((amd-gpu-targets . ,targets)
+       ,@(alist-delete 'amd-gpu-targets (package-properties p))))))
+
+(define (assert-valid-amd-gpu-targets package targets)
+  "Raise an error if the AMD GPU identifiers listed in TARGETS are not known
+to the compiler of PACKAGE."
+  (define (compiler-amd-gpu-targets package)
+    (assoc-ref (package-properties package) 'compiler-amd-gpu-targets))
+
+  (match (any (match-lambda
+                ((label (? package? package))
+                 (and (compiler-amd-gpu-targets package)
+                      package))
+                (_ #f))
+              (package-direct-inputs package))
+    (#f
+     (raise (make-compound-condition
+             (formatted-message
+              (G_ "~a: no ROCm compiler was found among the inputs")
+              (package-full-name package))
+             (condition (&error-location
+                         (location (package-location package)))))))
+    (compiler
+     (let ((supported (compiler-amd-gpu-targets compiler)))
+       ;; This is quadratic but on small lists.
+       (and=> (find (negate (cut member <> supported)) targets)
+              (lambda (unsupported)
+                (raise
+                 (make-compound-condition
+                  (formatted-message
+                   (G_ "compiler ~a does not support AMD GPU target ~a")
+                   (package-full-name compiler) unsupported)
+                  (condition (&error-location
+                              (location (package-location compiler))))
+                  (condition
+                   (&fix-hint
+                    (hint (format #f (G_ "Compiler ~a supports the following
+AMD GPU targets:
+
+@quotation
+~a
+@end quotation")
+                                  (package-full-name compiler "@@")
+                                  (string-join supported ", ")))))))))))))
+
+(define package-amd-gpu-specialization
+  (mlambda (targets)
+    "Return a procedure that maps the given package to its counterpart built
+for the given ROCm TARGETS, a list of GPU architectures."
+    (define rewriting-property
+      (gensym " package-amd-gpu-specialization"))
+
+    (define (mark p)
+      ;; Mark P as already processed.
+      (package/inherit p
+        (properties `((,rewriting-property . #t)
+                      ,@(package-properties p)))))
+
+    (package-mapping (lambda (p)
+                       (cond ((assq rewriting-property (package-properties p))
+                              p)
+                             ((assq 'amd-gpu-targets (package-properties p))
+                              (assert-valid-amd-gpu-targets p targets)
+                              (info (N_ "compiling ~a for AMD GPU~{ ~a~}~%"
+                                        "compiling ~a for these AMD GPUs:~{ 
~a~}~%"
+                                        (length targets))
+                                    (package-full-name p) targets)
+                              (mark (package-for-amd-gpu-targets p targets)))
+                             (else
+                              p)))
+                     (lambda (p)
+                       (assq rewriting-property (package-properties p)))
+                     #:deep? #t)))
+
+(define (transform-package-amd-gpu-targets targets)
+  "Return a procedure that, when applied to a package, returns that package
+such that the package itself and all its dependencies are specialized for
+TARGET-LIST, a list of strings denoting AMD GPUs."
+  (match targets
+    ((targets _ ...)
+     (let* ((rewrite (package-amd-gpu-specialization targets)))
+       (lambda (obj)
+         (if (package? obj)
+             (rewrite obj)
+             obj))))))
+
 (define (transform-package-with-debug-info specs)
   "Return a procedure that, when passed a package, set its 'replacement' field
 to the same package but with #:strip-binaries? #f in its 'arguments' field."
@@ -999,6 +1090,7 @@ are replaced by the specified upstream version."
     (with-git-url . ,transform-package-source-git-url)
     (with-c-toolchain . ,transform-package-toolchain)
     (tune . ,transform-package-tuning)
+    (amd-gpu . ,transform-package-amd-gpu-targets)
     (with-debug-info . ,transform-package-with-debug-info)
     (without-tests . ,transform-package-tests)
     (with-configure-flag . ,transform-package-configure-flag)
@@ -1085,6 +1177,11 @@ building for ~a instead of ~a, so tuning cannot be 
guessed~%")
                                            result)
                                (alist-delete 'tune result))
                            rest)))
+          (option '("amd-gpu") #t #f
+                  (lambda (opt name arg result . rest)
+                    (apply values
+                           (alist-cons 'amd-gpu (split-on-commas arg) result)
+                           rest)))
           (option '("with-debug-info") #t #f
                   (parser 'with-debug-info))
           (option '("without-tests") #t #f
diff --git a/tests/transformations.scm b/tests/transformations.scm
index 9f5aacc41b..1db54a0e19 100644
--- a/tests/transformations.scm
+++ b/tests/transformations.scm
@@ -1,5 +1,5 @@
 ;;; GNU Guix --- Functional package management for GNU
-;;; Copyright © 2016-2017, 2019-2024 Ludovic Courtès <[email protected]>
+;;; Copyright © 2016-2017, 2019-2024, 2026 Ludovic Courtès <[email protected]>
 ;;; Copyright © 2021 Marius Bakke <[email protected]>
 ;;;
 ;;; This file is part of GNU Guix.
@@ -638,6 +638,45 @@
       (package->bag (t p))
       #f)))
 
+(test-equal "options->transformations, amd-gpu"
+  '("gfx90a" "gfx942")
+  (let ((p (dummy-package "amd-gpu-code"
+             (native-inputs
+              (list (@ (gnu packages llvm) clang-rocm)))
+             (properties '((amd-gpu-targets . ("whatever"))))))
+        (t (options->transformation '((amd-gpu . ("gfx90a" "gfx942"))))))
+    (assoc-ref (package-properties (t p)) 'amd-gpu-targets)))
+
+(test-equal "options->transformations, amd-gpu, not applicable"
+  #f
+  (let ((p (dummy-package "not-amd-gpu-code"))
+        (t (options->transformation '((amd-gpu . ("gfx90a" "gfx942"))))))
+    (assoc-ref (package-properties (t p)) 'amd-gpu-targets)))
+
+(test-assert "options->transformations, amd-gpu, missing clang-rocm input"
+  (let ((p (dummy-package "amd-gpu-code"
+             (properties '((amd-gpu-targets . ("whatever"))))))
+        (t (options->transformation '((amd-gpu . ("generic"))))))
+    ;; Since 'clang-rocm' is not among the inputs, an error should be raised.
+    (guard (c ((formatted-message? c)
+               (string-contains (formatted-message-string c)
+                                "no ROCm compiler")))
+      (t p)
+      #f)))
+
+(test-assert "options->transformations, amd-gpu, wrong GPU"
+  (let ((p (dummy-package "amd-gpu-code"
+             (native-inputs
+              (list (@ (gnu packages llvm) clang-rocm)))
+             (properties '((amd-gpu-targets . ("whatever"))))))
+        (t (options->transformation '((amd-gpu . ("does-not-exist"))))))
+    ;; Since this AMD GPU target is not known to 'clang-rocm', an error should
+    ;; be raised.
+    (guard (c ((formatted-message? c)
+               (member "does-not-exist" (formatted-message-arguments c))))
+      (t p)
+      #f)))
+
 (test-equal "options->transformation + package->manifest-entry"
   '((transformations . ((without-tests . "foo"))))
   (let* ((p (dummy-package "foo"))

Reply via email to