summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/arm.configure
blob: 5d26f4d73239182a0b139db3e739cbe3e3152957 (plain)
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
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# -*- 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/.


@depends(target.os)
def arm_option_defaults(os):
    if os == "Android":
        arch = "armv7-a"
        thumb = "yes"
        fpu = "neon"
        float_abi = "softfp"
    else:
        arch = thumb = fpu = float_abi = "toolchain-default"
    return namespace(
        arch=arch,
        thumb=thumb,
        fpu=fpu,
        float_abi=float_abi,
    )


# Note: '{...|}' in the help of all options with a non-constant default to
# make the lint happy. The first arm is always going to be used, because a
# default is always returned. The lint is fooled by this file being
# conditional. If it weren't conditional, the lint wouldn't ask for '{|}' to
# be there.
option(
    "--with-arch",
    nargs=1,
    default=arm_option_defaults.arch,
    help="{Use specific CPU features (-march=type). Resets thumb, fpu, "
    "float-abi, etc. defaults when set|}",
)


@depends("--with-arch")
def arch_option(value):
    if value:
        if value[0] != "toolchain-default":
            return ["-march={}".format(value[0])]
    return []


option(
    "--with-thumb",
    choices=("yes", "no", "toolchain-default"),
    default=arm_option_defaults.thumb,
    nargs="?",
    help="{Use Thumb instruction set (-mthumb)|}",
)


def normalize_arm_option(value):
    if value:
        if len(value):
            if value[0] == "yes":
                return True
            elif value[0] == "no":
                return False
            else:
                return value[0]
        return True
    return False


@depends("--with-thumb")
def thumb_option(value):
    value = normalize_arm_option(value)
    if value is True:
        return ["-mthumb"]
    if value is False:
        return ["-marm"]
    return []


option(
    "--with-thumb-interwork",
    choices=("yes", "no", "toolchain-default"),
    default="toolchain-default",
    nargs="?",
    help="Use Thumb/ARM instuctions interwork (-mthumb-interwork)",
)


@depends("--with-thumb-interwork")
def thumb_interwork_option(value):
    value = normalize_arm_option(value)
    if value is True:
        return ["-mthumb-interwork"]
    if value is False:
        return ["-mno-thumb-interwork"]
    return []


option(
    "--with-fpu",
    nargs=1,
    default=arm_option_defaults.fpu,
    help="{Use specific FPU type (-mfpu=type)|}",
)


@depends("--with-fpu")
def fpu_option(value):
    if value:
        if value[0] != "toolchain-default":
            return ["-mfpu={}".format(value[0])]
    return []


option(
    "--with-float-abi",
    nargs=1,
    default=arm_option_defaults.float_abi,
    help="{Use specific arm float ABI (-mfloat-abi=type)|}",
)


@depends("--with-float-abi")
def float_abi_option(value):
    if value:
        if value[0] != "toolchain-default":
            return ["-mfloat-abi={}".format(value[0])]
    return []


option(
    "--with-soft-float",
    choices=("yes", "no", "toolchain-default"),
    default="toolchain-default",
    nargs="?",
    help="Use soft float library (-msoft-float)",
)


@depends("--with-soft-float")
def soft_float_option(value):
    value = normalize_arm_option(value)
    if value is True:
        return ["-msoft-float"]
    if value is False:
        return ["-mno-soft-float"]
    return []


check_and_add_flag(
    "-mno-unaligned-access", when=depends(target.os)(lambda os: os == "Android")
)


# The set of flags that clang understands
@depends(
    arch_option,
    thumb_option,
    fpu_option,
    float_abi_option,
    soft_float_option,
)
def all_clang_arm_flags(arch, thumb, fpu, float_abi, soft_float):
    return arch + thumb + fpu + float_abi + soft_float


# All the flags the compiler understands. When the compiler is clang, this
# still includes unsupported flags, but we live it to configure to fail
# during a compiler check. These checks aren't available for clang as used
# by bindgen, so we keep the separate set of flags for clang for bindgen.
@depends(all_clang_arm_flags, thumb_interwork_option)
def all_arm_flags(flags, interwork):
    return flags + interwork


add_old_configure_assignment("_ARM_FLAGS", all_arm_flags)
add_old_configure_assignment("_THUMB_FLAGS", thumb_option)


@depends(configure_cache, c_compiler, all_arm_flags)
@checking("ARM version support in compiler", lambda x: x.arm_arch)
@imports(_from="textwrap", _import="dedent")
def arm_target(configure_cache, compiler, all_arm_flags):
    # We're going to preprocess the following source to figure out some details
    # about the arm target options we have enabled.
    source = dedent(
        """\
        %ARM_ARCH __ARM_ARCH
        #if __thumb2__
        %THUMB2 yes
        #else
        %THUMB2 no
        #endif
        // Confusingly, the __SOFTFP__ preprocessor variable indicates the
        // "softfloat" ABI, not the "softfp" ABI.
        #if __SOFTFP__
        %FLOAT_ABI soft
        #elif __ARM_PCS_VFP
        %FLOAT_ABI hard
        #else
        %FLOAT_ABI softfp
        #endif
        // There is more subtlety to it than this preprocessor test, but MOZ_FPU doesn't
        // need to be too fine-grained.
        #if __ARM_NEON
        %FPU neon
        #elif __ARM_VFPV2__ || __ARM_FP == 12
        %FPU vfpv2
        #elif __ARM_VFPV3__
        %FPU vfpv3
        #elif __ARM_VFPV4__ || __ARM_FP == 14
        %FPU vfpv4
        #elif __ARM_FPV5__
        %FPU fp-armv8
        #endif
    """
    )
    result = try_invoke_compiler(
        configure_cache,
        [compiler.compiler] + compiler.flags,
        compiler.language,
        source,
        ["-E"] + all_arm_flags,
        wrapper=compiler.wrapper,
    )
    # Metadata emitted by preprocessors such as GCC with LANG=ja_JP.utf-8 may
    # have non-ASCII characters. Treat the output as bytearray.
    data = {"fpu": None}  # fpu may not get a value from the preprocessor.
    for line in result.splitlines():
        if line.startswith("%"):
            k, _, v = line.partition(" ")
            k = k.lstrip("%").lower()
            if k == "arm_arch":
                data[k] = int(v)
            else:
                data[k] = {
                    "yes": True,
                    "no": False,
                }.get(v, v)
            log.debug("%s = %s", k, data[k])

    return namespace(**data)


@depends(arm_target.arm_arch, when=depends(target.os)(lambda os: os == "Android"))
def armv7(arch):
    if arch < 7:
        die("Android/armv6 and earlier are not supported")


set_config("MOZ_THUMB2", True, when=arm_target.thumb2)
set_define("MOZ_THUMB2", True, when=arm_target.thumb2)


have_arm_simd = c_compiler.try_compile(
    body='asm("uqadd8 r1, r1, r2");', check_msg="for ARM SIMD support in compiler"
)

set_config("HAVE_ARM_SIMD", have_arm_simd)
set_define("HAVE_ARM_SIMD", have_arm_simd)

have_arm_neon = c_compiler.try_compile(
    body='asm(".fpu neon\\n vadd.i8 d0, d0, d0");',
    check_msg="for ARM NEON support in compiler",
)

set_config("HAVE_ARM_NEON", have_arm_neon)
set_define("HAVE_ARM_NEON", have_arm_neon)


# We don't need to build NEON support if we're targetting a non-NEON device.
# This matches media/webrtc/trunk/webrtc/build/common.gypi.
@depends(arm_target.arm_arch, when=have_arm_neon)
def build_arm_neon(arm_arch):
    return arm_arch >= 7


set_config("BUILD_ARM_NEON", True, when=build_arm_neon)
set_define("BUILD_ARM_NEON", True, when=build_arm_neon)


set_config("ARM_ARCH", depends(arm_target.arm_arch)(lambda x: str(x)))
set_config("MOZ_FPU", arm_target.fpu)


@depends(arm_target)
def neon_flags(arm_target):
    # Building with -mfpu=neon requires either the "softfp" or the
    # "hardfp" ABI. Depending on the compiler's default target, and the
    # CFLAGS, the default ABI might be neither, in which case it is the
    # "softfloat" ABI.
    # The "softfloat" ABI is binary-compatible with the "softfp" ABI, so
    # we can safely mix code built with both ABIs. So, if we detect
    # that compiling uses the "softfloat" ABI, force the use of the
    # "softfp" ABI instead.
    flags = ["-mfpu=neon"]
    if arm_target.float_abi == "soft":
        flags.append("-mfloat-abi=softfp")
    if arm_target.arm_arch < 7:
        # clang needs to be forced to at least armv7 for -mfpu=neon to do
        # something.
        flags.append("-march=armv7-a")
    return tuple(flags)


set_config("NEON_FLAGS", neon_flags)