From 0b2036cad0c49e9aeb0c9b9feac9f734016460d3 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Wed, 7 Dec 2022 18:56:32 -0800 Subject: [PATCH] cc-wrapper: fix -mtune= validation, add ARM, add fallbacks Before this commit, cc-wrapper/default.nix was using `isGccArchSupported` to validate `-mtune=` values. This has two problems: - On x86, `-mtune=` can take the same values as `-march`, plus two additional values `generic` and `intel` which are not valid for `-march`. - On ARM, `-mtune=` does not take the same values as `-march=`; instead it takes the same values as `-mcpu`. This commit fixes these two problems by adding a new `isGccTuneSupported` function. For `isx86` this returns `true` for the two special values and otherwise defers to `isGccArchSupported`. This commit also adds support for `-mtune=` on Aarch64. Unfortunately on Aarch64, Clang does not accept as wide a variety of `-mtune=` values as Gcc does. In particular, Clang does not tune for big.LITTLE mixed-model chips like the very popular RK3399, which is targeted using `-march=cortex-a72.cortex-a53` in gcc. To address this problem, this commit also adds a function `findBestTuneApproximation` which can be used to map clang-unsupported tunings like `cortex-a72.cortex-a53` to less-precise tunings like `cortex-a53`. The work which led to this commit arose because we now have packages, like `crosvm`, which use *both* `clang` *and* `gcc`. Previously I had been using `overrideAttrs` to set `NIX_CFLAGS_COMPILE` on a package-by-package basis based on which compiler that package used. Since we now have packages which use *both* compilers, this strategy no longer works. I briefly considered splitting `NIX_CFLAGS_COMPILE` into `NIX_CFLAGS_COMPILE_GCC` and `NIX_CFLAGS_COMPILE_CLANG`, but since `NIX_CFLAGS_COMPILE` is sort of a hack to begin with I figured that adding the logic to `cc-wrapper` would be preferable. --- pkgs/build-support/cc-wrapper/default.nix | 70 +++++++++++++++++++++-- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/pkgs/build-support/cc-wrapper/default.nix b/pkgs/build-support/cc-wrapper/default.nix index eef67154ef94..8ac11436c5f7 100644 --- a/pkgs/build-support/cc-wrapper/default.nix +++ b/pkgs/build-support/cc-wrapper/default.nix @@ -110,7 +110,20 @@ let gccForLibs_solib = getLib gccForLibs + optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}"; - # older compilers (for example bootstrap's GCC 5) fail with -march=too-modern-cpu + # The following two functions, `isGccArchSupported` and + # `isGccTuneSupported`, only handle those situations where a flag + # (`-march` or `-mtune`) is accepted by one compiler but rejected + # by another, and both compilers are relevant to nixpkgs. We are + # not trying to maintain a complete list of all flags accepted by + # all versions of all compilers ever in nixpkgs. + # + # The two main cases of interest are: + # + # - One compiler is gcc and the other is clang + # - One compiler is pkgs.gcc and the other is bootstrap-files.gcc + # -- older compilers (for example bootstrap's GCC 5) fail with + # -march=too-modern-cpu + isGccArchSupported = arch: if targetPlatform.isPower then false else # powerpc does not allow -march= if isGNU then @@ -159,6 +172,51 @@ let else false; + isGccTuneSupported = tune: + # for x86 -mtune= takes the same values as -march, plus two more: + if targetPlatform.isx86 then + { + generic = true; + intel = true; + }.${tune} or (isGccArchSupported tune) + # on arm64, the -mtune= values are specific processors + else if targetPlatform.isAarch64 then + (if isGNU then + { + cortex-a53 = versionAtLeast ccVersion "4.8"; # gcc 8c075f + cortex-a72 = versionAtLeast ccVersion "5.1"; # gcc d8f70d + "cortex-a72.cortex-a53" = versionAtLeast ccVersion "5.1"; # gcc d8f70d + }.${tune} or false + else if isClang then + { + cortex-a53 = versionAtLeast ccVersion "3.9"; # llvm dfc5d1 + }.${tune} or false + else false) + else if targetPlatform.isPower then + # powerpc does not support -march + true + else if targetPlatform.isMips then + # for mips -mtune= takes the same values as -march + isGccArchSupported tune + else + false; + + # Clang does not support as many `-mtune=` values as gcc does; + # this function will return the best possible approximation of the + # provided `-mtune=` value, or `null` if none exists. + # + # Note: this function can make use of ccVersion; for example, `if + # versionOlder ccVersion "12" then ...` + findBestTuneApproximation = tune: + let guess = if isClang + then { + # clang does not tune for big.LITTLE chips + "cortex-a72.cortex-a53" = "cortex-a72"; + }.${tune} or tune + else tune; + in if isGccTuneSupported guess + then guess + else null; darwinPlatformForCC = optionalString stdenv.targetPlatform.isDarwin ( if (targetPlatform.darwinPlatform == "macos" && isGNU) then "macosx" @@ -559,10 +617,12 @@ stdenv.mkDerivation { + optionalString (targetPlatform ? gcc.thumb) '' echo "-m${if targetPlatform.gcc.thumb then "thumb" else "arm"}" >> $out/nix-support/cc-cflags-before '' - + optionalString (targetPlatform ? gcc.tune && - isGccArchSupported targetPlatform.gcc.tune) '' - echo "-mtune=${targetPlatform.gcc.tune}" >> $out/nix-support/cc-cflags-before - '' + + (let tune = if targetPlatform ? gcc.tune + then findBestTuneApproximation targetPlatform.gcc.tune + else null; + in optionalString (tune != null) '' + echo "-mtune=${tune}" >> $out/nix-support/cc-cflags-before + '') # TODO: categorize these and figure out a better place for them + optionalString targetPlatform.isWindows ''