DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Mercurial (ed839e4a3021)

VCS Links

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.

# PGO
# ==============================================================
llvm_profdata = check_prog('LLVM_PROFDATA', ['llvm-profdata'],
                           allow_missing=True,
                           paths=toolchain_search_path)

js_option('--enable-profile-generate',
          nargs='?',
          choices=('cross',),
          help='Build a PGO instrumented binary')

imply_option('MOZ_PGO',
             depends_if('--enable-profile-generate')(lambda _: True))

set_config('MOZ_PROFILE_GENERATE',
           depends_if('--enable-profile-generate')(lambda _: True))

set_define('MOZ_PROFILE_GENERATE',
           depends_if('--enable-profile-generate')(lambda _: True))

js_option('--enable-profile-use',
          nargs='?',
          choices=('cross',),
          help='Use a generated profile during the build')

js_option('--with-pgo-profile-path',
          help='Path to the directory with unmerged profile data to use during the build',
          nargs=1)

js_option('--enable-cross-pgo',
          help='Enable PGO on Rust code')

imply_option('MOZ_PGO',
             depends_if('--enable-profile-use')(lambda _: True))

set_config('MOZ_PROFILE_USE',
           depends_if('--enable-profile-use')(lambda _: True))


@depends('--with-pgo-profile-path', '--enable-profile-use', llvm_profdata, check_build_environment)
@imports('os')
def pgo_profile_path(path, pgo_use, profdata, build_env):
    topobjdir = build_env.topobjdir
    if topobjdir.endswith('/js/src'):
        topobjdir = topobjdir[:-7]

    if not path:
        return os.path.join(topobjdir, 'merged.profdata')
    if path and not pgo_use:
        die('Pass --enable-profile-use to use --with-pgo-profile-path.')
    if path and not profdata:
        die('LLVM_PROFDATA must be set to process the pgo profile.')
    if not os.path.isfile(path[0]):
        die('Argument to --with-pgo-profile-path must be a file.')
    if not os.path.isabs(path[0]):
        die('Argument to --with-pgo-profile-path must be an absolute path.')
    return path[0]


set_config('PGO_PROFILE_PATH', pgo_profile_path)

@depends(c_compiler, target, pgo_profile_path)
@imports('multiprocessing')
@imports(_from='__builtin__', _import='min')
def pgo_flags(compiler, target, profdata):
    if compiler.type == 'gcc':
        return namespace(
            gen_cflags=['-fprofile-generate'],
            gen_ldflags=['-fprofile-generate'],
            use_cflags=['-fprofile-use', '-fprofile-correction',
                        '-Wcoverage-mismatch'],
            use_ldflags=['-fprofile-use'],
        )

    if compiler.type in ('clang-cl', 'clang'):
        prefix = ''
        if compiler.type == 'clang-cl':
            prefix = '/clang:'
            if target.cpu == 'x86_64':
                gen_ldflags = ['clang_rt.profile-x86_64.lib']
            elif target.cpu == 'x86':
                gen_ldflags = ['clang_rt.profile-i386.lib']
            else:
                gen_ldflags = None
        else:
            gen_ldflags = ['-fprofile-generate']

        return namespace(
            gen_cflags=[prefix + '-fprofile-generate'],
            gen_ldflags=gen_ldflags,
            use_cflags=[prefix + '-fprofile-use=%s' % profdata,
                        # Some error messages about mismatched profile data
                        # come in via -Wbackend-plugin, so disable those too.
                        '-Wno-error=backend-plugin'],
            use_ldflags=[],
        )


set_config('PROFILE_GEN_CFLAGS', pgo_flags.gen_cflags)
set_config('PROFILE_GEN_LDFLAGS', pgo_flags.gen_ldflags)
set_config('PROFILE_USE_CFLAGS', pgo_flags.use_cflags)
set_config('PROFILE_USE_LDFLAGS', pgo_flags.use_ldflags)

option('--with-pgo-jarlog',
       help='Use the provided jarlog file when packaging during a profile-use '
            'build',
       nargs=1)

set_config('PGO_JARLOG_PATH', depends_if('--with-pgo-jarlog')(lambda p: p))


@depends('MOZ_PGO', '--enable-profile-use', '--enable-profile-generate',
         c_compiler, rustc_info)
def moz_pgo_rust(pgo, profile_use, profile_generate, c_compiler, rustc):
    if not pgo:
        return

    # Enabling PGO through MOZ_PGO only and not --enable* flags.
    if not profile_use and not profile_generate:
        return

    if profile_use and profile_generate:
        die('Cannot build with --enable-profile-use and --enable-profile-generate.')

    want_cross = (len(profile_use) and profile_use[0] == 'cross') \
                 or (len(profile_generate) and profile_generate[0] == 'cross')

    if not want_cross:
        return

    if c_compiler.type == 'gcc':
        die('Cannot use cross-language PGO with GCC.')

    # PGO is not stable prior to 1.37
    if rustc.version < Version('1.37'):
        die('Cannot use cross-language PGO with Rust version %s.' % rustc.version)

    return True

set_config('MOZ_PGO_RUST', moz_pgo_rust)

# LTO
# ==============================================================

js_option('--enable-lto',
          env='MOZ_LTO',
          nargs='?',
          choices=('full', 'thin', 'cross'),
          help='Enable LTO')

js_option(env='MOZ_LD64_KNOWN_GOOD',
          nargs=1,
          help='Indicate that ld64 is free of symbol aliasing bugs.')

imply_option('MOZ_LD64_KNOWN_GOOD', depends_if('MOZ_AUTOMATION')(lambda _: True))

@depends('--enable-lto', c_compiler, 'MOZ_LD64_KNOWN_GOOD', target)
@imports('multiprocessing')
def lto(value, c_compiler, ld64_known_good, target):
    cflags = []
    ldflags = []
    enabled = None
    rust_lto = False

    if value:
        enabled = True
        # `cross` implies `thin`, but with Rust code participating in LTO
        # as well.  Make that a little more explicit.
        if len(value) and value[0].lower() == 'cross':
            if c_compiler.type == 'gcc':
                die('Cross-language LTO is not supported with GCC.')

            rust_lto = True
            value = ['thin']

        if target.kernel == 'Darwin' and target.os == 'OSX' \
           and value[0].lower() == 'cross' and not ld64_known_good:
            die('The Mac linker is known to have a bug that affects cross-language '
                'LTO.  If you know that your linker is free from this bug, please '
                'set the environment variable `MOZ_LD64_KNOWN_GOOD=1` and re-run '
                'configure.')

        if c_compiler.type == 'clang':
            if len(value) and value[0].lower() == 'full':
                cflags.append("-flto")
                ldflags.append("-flto")
            else:
                cflags.append("-flto=thin")
                ldflags.append("-flto=thin")
        elif c_compiler.type == 'clang-cl':
            if len(value) and value[0].lower() == 'full':
                cflags.append("-flto")
            else:
                cflags.append("-flto=thin")
            # With clang-cl, -flto can only be used with -c or -fuse-ld=lld.
            # AC_TRY_LINKs during configure don't have -c, so pass -fuse-ld=lld.
            cflags.append("-fuse-ld=lld");

            # Explicitly set the CPU to optimize for so the linker doesn't
            # choose a poor default.  Rust compilation by default uses the
            # pentium4 CPU on x86:
            #
            # https://github.com/rust-lang/rust/blob/master/src/librustc_target/spec/i686_pc_windows_msvc.rs#L5
            #
            # which specifically supports "long" (multi-byte) nops.  See
            # https://bugzilla.mozilla.org/show_bug.cgi?id=1568450#c8 for details.
            #
            # The pentium4 seems like kind of a weird CPU to optimize for, but
            # it seems to have worked out OK thus far.  LLVM does not seem to
            # specifically schedule code for the pentium4's deep pipeline, so
            # that probably contributes to it being an OK default for our
            # purposes.
            if target.cpu == 'x86':
                ldflags.append('-mllvm:-mcpu=pentium4')
            # This is also the CPU that Rust uses.  The LLVM source code
            # recommends this as the "generic 64-bit specific x86 processor model":
            #
            # https://github.com/llvm/llvm-project/blob/e7694f34ab6a12b8bb480cbfcb396d0a64fe965f/llvm/lib/Target/X86/X86.td#L1165-L1187
            if target.cpu == 'x86_64':
                ldflags.append('-mllvm:-mcpu=x86-64')
            # We do not need special flags for arm64.  Hooray for fixed-length
            # instruction sets.
        else:
            num_cores = multiprocessing.cpu_count()
            cflags.append("-flto")
            cflags.append("-flifetime-dse=1")

            ldflags.append("-flto=%s" % num_cores)
            ldflags.append("-flifetime-dse=1")

        # Tell LTO not to inline functions above a certain size, to mitigate
        # binary size growth while still getting good performance.
        # (For hot functions, PGO will put a multiplier on this limit.)
        if target.os == 'WINNT':
            ldflags.append('-mllvm:-import-instr-limit=10');
        elif target.os == 'OSX':
            # Until OSX gets PGO, too small of a limit will cause slowdowns.
            ldflags.append('-Wl,-mllvm,-import-instr-limit=40');
        elif c_compiler.type == 'clang':
            ldflags.append('-Wl,-plugin-opt=-import-instr-limit=10');

    return namespace(
        enabled=enabled,
        cflags=cflags,
        ldflags=ldflags,
        rust_lto=rust_lto,
    )


add_old_configure_assignment('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO', lto.enabled)
set_define('MOZ_LTO', lto.enabled)
set_config('MOZ_LTO_CFLAGS', lto.cflags)
set_config('MOZ_LTO_LDFLAGS', lto.ldflags)
set_config('MOZ_LTO_RUST', lto.rust_lto)
add_old_configure_assignment('MOZ_LTO_CFLAGS', lto.cflags)
add_old_configure_assignment('MOZ_LTO_LDFLAGS', lto.ldflags)