1# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
2# vim: set filetype=python:
3# This Source Code Form is subject to the terms of the Mozilla Public
4# License, v. 2.0. If a copy of the MPL was not distributed with this
5# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7
8@depends(target.os)
9def arm_option_defaults(os):
10    if os == "Android":
11        arch = "armv7-a"
12        thumb = "yes"
13        fpu = "neon"
14        float_abi = "softfp"
15    else:
16        arch = thumb = fpu = float_abi = "toolchain-default"
17    return namespace(
18        arch=arch,
19        thumb=thumb,
20        fpu=fpu,
21        float_abi=float_abi,
22    )
23
24
25# Note: '{...|}' in the help of all options with a non-constant default to
26# make the lint happy. The first arm is always going to be used, because a
27# default is always returned. The lint is fooled by this file being
28# conditional. If it weren't conditional, the lint wouldn't ask for '{|}' to
29# be there.
30option(
31    "--with-arch",
32    nargs=1,
33    default=arm_option_defaults.arch,
34    help="{Use specific CPU features (-march=type). Resets thumb, fpu, "
35    "float-abi, etc. defaults when set|}",
36)
37
38
39@depends("--with-arch")
40def arch_option(value):
41    if value:
42        if value[0] != "toolchain-default":
43            return ["-march={}".format(value[0])]
44    return []
45
46
47option(
48    "--with-thumb",
49    choices=("yes", "no", "toolchain-default"),
50    default=arm_option_defaults.thumb,
51    nargs="?",
52    help="{Use Thumb instruction set (-mthumb)|}",
53)
54
55
56def normalize_arm_option(value):
57    if value:
58        if len(value):
59            if value[0] == "yes":
60                return True
61            elif value[0] == "no":
62                return False
63            else:
64                return value[0]
65        return True
66    return False
67
68
69@depends("--with-thumb")
70def thumb_option(value):
71    value = normalize_arm_option(value)
72    if value is True:
73        return ["-mthumb"]
74    if value is False:
75        return ["-marm"]
76    return []
77
78
79option(
80    "--with-thumb-interwork",
81    choices=("yes", "no", "toolchain-default"),
82    default="toolchain-default",
83    nargs="?",
84    help="Use Thumb/ARM instuctions interwork (-mthumb-interwork)",
85)
86
87
88@depends("--with-thumb-interwork")
89def thumb_interwork_option(value):
90    value = normalize_arm_option(value)
91    if value is True:
92        return ["-mthumb-interwork"]
93    if value is False:
94        return ["-mno-thumb-interwork"]
95    return []
96
97
98option(
99    "--with-fpu",
100    nargs=1,
101    default=arm_option_defaults.fpu,
102    help="{Use specific FPU type (-mfpu=type)|}",
103)
104
105
106@depends("--with-fpu")
107def fpu_option(value):
108    if value:
109        if value[0] != "toolchain-default":
110            return ["-mfpu={}".format(value[0])]
111    return []
112
113
114option(
115    "--with-float-abi",
116    nargs=1,
117    default=arm_option_defaults.float_abi,
118    help="{Use specific arm float ABI (-mfloat-abi=type)|}",
119)
120
121
122@depends("--with-float-abi")
123def float_abi_option(value):
124    if value:
125        if value[0] != "toolchain-default":
126            return ["-mfloat-abi={}".format(value[0])]
127    return []
128
129
130option(
131    "--with-soft-float",
132    choices=("yes", "no", "toolchain-default"),
133    default="toolchain-default",
134    nargs="?",
135    help="Use soft float library (-msoft-float)",
136)
137
138
139@depends("--with-soft-float")
140def soft_float_option(value):
141    value = normalize_arm_option(value)
142    if value is True:
143        return ["-msoft-float"]
144    if value is False:
145        return ["-mno-soft-float"]
146    return []
147
148
149check_and_add_gcc_flag(
150    "-mno-unaligned-access", when=depends(target.os)(lambda os: os == "Android")
151)
152
153
154@depends(
155    arch_option,
156    thumb_option,
157    thumb_interwork_option,
158    fpu_option,
159    float_abi_option,
160    soft_float_option,
161)
162def all_flags(arch, thumb, interwork, fpu, float_abi, soft_float):
163    return arch + thumb + interwork + fpu + float_abi + soft_float
164
165
166add_old_configure_assignment("_ARM_FLAGS", all_flags)
167add_old_configure_assignment("_THUMB_FLAGS", thumb_option)
168
169
170@depends(c_compiler, all_flags)
171@checking("ARM version support in compiler", lambda x: x.arm_arch)
172@imports(_from="textwrap", _import="dedent")
173def arm_target(compiler, all_flags):
174    # We're going to preprocess the following source to figure out some details
175    # about the arm target options we have enabled.
176    source = dedent(
177        """\
178        %ARM_ARCH __ARM_ARCH
179        #if __thumb2__
180        %THUMB2 yes
181        #else
182        %THUMB2 no
183        #endif
184        // Confusingly, the __SOFTFP__ preprocessor variable indicates the
185        // "softfloat" ABI, not the "softfp" ABI.
186        #if __SOFTFP__
187        %FLOAT_ABI soft
188        #elif __ARM_PCS_VFP
189        %FLOAT_ABI hard
190        #else
191        %FLOAT_ABI softfp
192        #endif
193        // There is more subtlety to it than this preprocessor test, but MOZ_FPU doesn't
194        // need to be too fine-grained.
195        #if __ARM_NEON
196        %FPU neon
197        #elif __ARM_VFPV2__ || __ARM_FP == 12
198        %FPU vfpv2
199        #elif __ARM_VFPV3__
200        %FPU vfpv3
201        #elif __ARM_VFPV4__ || __ARM_FP == 14
202        %FPU vfpv4
203        #elif __ARM_FPV5__
204        %FPU fp-armv8
205        #endif
206    """
207    )
208    result = try_invoke_compiler(
209        compiler.wrapper + [compiler.compiler] + compiler.flags,
210        compiler.language,
211        source,
212        ["-E"] + all_flags,
213    )
214    # Metadata emitted by preprocessors such as GCC with LANG=ja_JP.utf-8 may
215    # have non-ASCII characters. Treat the output as bytearray.
216    data = {"fpu": None}  # fpu may not get a value from the preprocessor.
217    for line in result.splitlines():
218        if line.startswith("%"):
219            k, _, v = line.partition(" ")
220            k = k.lstrip("%").lower()
221            if k == "arm_arch":
222                data[k] = int(v)
223            else:
224                data[k] = {
225                    "yes": True,
226                    "no": False,
227                }.get(v, v)
228            log.debug("%s = %s", k, data[k])
229
230    return namespace(**data)
231
232
233@depends(arm_target.arm_arch, when=depends(target.os)(lambda os: os == "Android"))
234def armv7(arch):
235    if arch < 7:
236        die("Android/armv6 and earlier are not supported")
237
238
239set_config("MOZ_THUMB2", True, when=arm_target.thumb2)
240set_define("MOZ_THUMB2", True, when=arm_target.thumb2)
241add_old_configure_assignment("MOZ_THUMB2", True, when=arm_target.thumb2)
242
243
244have_arm_simd = c_compiler.try_compile(
245    body='asm("uqadd8 r1, r1, r2");', check_msg="for ARM SIMD support in compiler"
246)
247
248set_config("HAVE_ARM_SIMD", have_arm_simd)
249set_define("HAVE_ARM_SIMD", have_arm_simd)
250
251have_arm_neon = c_compiler.try_compile(
252    body='asm(".fpu neon\\n vadd.i8 d0, d0, d0");',
253    check_msg="for ARM NEON support in compiler",
254)
255
256set_config("HAVE_ARM_NEON", have_arm_neon)
257set_define("HAVE_ARM_NEON", have_arm_neon)
258
259
260# We don't need to build NEON support if we're targetting a non-NEON device.
261# This matches media/webrtc/trunk/webrtc/build/common.gypi.
262@depends(arm_target.arm_arch, when=have_arm_neon)
263def build_arm_neon(arm_arch):
264    return arm_arch >= 7
265
266
267set_config("BUILD_ARM_NEON", build_arm_neon)
268set_define("BUILD_ARM_NEON", build_arm_neon)
269
270
271set_config("ARM_ARCH", depends(arm_target.arm_arch)(lambda x: str(x)))
272add_old_configure_assignment("ARM_ARCH", depends(arm_target.arm_arch)(lambda x: str(x)))
273set_config("MOZ_FPU", arm_target.fpu)
274
275
276@depends(arm_target.float_abi)
277def neon_flags(float_abi):
278    # Building with -mfpu=neon requires either the "softfp" or the
279    # "hardfp" ABI. Depending on the compiler's default target, and the
280    # CFLAGS, the default ABI might be neither, in which case it is the
281    # "softfloat" ABI.
282    # The "softfloat" ABI is binary-compatible with the "softfp" ABI, so
283    # we can safely mix code built with both ABIs. So, if we detect
284    # that compiling uses the "softfloat" ABI, force the use of the
285    # "softfp" ABI instead.
286    flags = ["-mfpu=neon"]
287    if float_abi == "soft":
288        flags.append("-mfloat-abi=softfp")
289    return tuple(flags)
290
291
292set_config("NEON_FLAGS", neon_flags)
293