Skip to content

Commit 1835df7

Browse files
authored
Generate multilib.yaml for compatible architecture versions and features (#517)
This expands multilib-fpus.py (renaming it) to add Match blocks to split the -march options into two sets of options, which will be more useful for libray matching: * A -march= option for each minor version less than or equal to the selected one, so that it will be possible to mark a library as requiring one architecture version, and allowing it to be used for any later version. This strips any feature modifiers off the option, so that they can be matched independently of base architecture version. * A -march option for every feature modifier which is enabled or disabled. This uses the made-up architecture name "armvX", which isn't a valid option, but that doesn't matter to multilib, and this allows matching features independently of the base architecture version.
1 parent de4eb46 commit 1835df7

File tree

5 files changed

+152
-21
lines changed

5 files changed

+152
-21
lines changed

CMakeLists.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,7 +2037,7 @@ configure_file(
20372037
)
20382038

20392039
set(multilib_yaml_depends
2040-
"${CMAKE_CURRENT_SOURCE_DIR}/multilib-fpus.py"
2040+
"${CMAKE_CURRENT_SOURCE_DIR}/multilib-generate.py"
20412041
"${CMAKE_CURRENT_BINARY_DIR}/multilib-without-fpus.yaml"
20422042
)
20432043
if(LIBS_DEPEND_ON_TOOLS)
@@ -2049,7 +2049,7 @@ add_custom_command(
20492049
COMMAND ${CMAKE_COMMAND} -E copy
20502050
${CMAKE_CURRENT_BINARY_DIR}/multilib-without-fpus.yaml
20512051
${CMAKE_CURRENT_BINARY_DIR}/llvm/${TARGET_LIBRARIES_DIR}${library_subdir}/multilib.yaml
2052-
COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/multilib-fpus.py"
2052+
COMMAND ${Python3_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/multilib-generate.py"
20532053
"--clang=${LLVM_BINARY_DIR}/bin/clang${CMAKE_EXECUTABLE_SUFFIX}"
20542054
"--llvm-source=${llvmproject_SOURCE_DIR}"
20552055
>> "${CMAKE_CURRENT_BINARY_DIR}/llvm/${TARGET_LIBRARIES_DIR}${library_subdir}/multilib.yaml"

multilib-fpus.py renamed to multilib-generate.py

Lines changed: 120 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#!/usr/bin/env python3
22

3-
"""Auto-generate implications between -mfpu options for multilib.yaml.in.
3+
"""Auto-generate implications between command-line options options for
4+
multilib.yaml.in.
45
56
Each FPU name that clang knows about is mapped to all the FPU names
67
that clang considers to be a subset of it (determined by extracting
@@ -21,13 +22,28 @@
2122
d-registers, because the extra 16 d-registers are caller-saved, so
2223
setjmp and exceptions need not preserve them. Interrupt handlers would
2324
have to preserve them, but our libraries don't define any.
25+
26+
For architecture extension modifiers on the -march option, we expand these into
27+
options of the form -march=armvX+[no]feature, for each feature which is listed
28+
as enabled or disabled in the input options. Each of these new options has
29+
exactly one feature, so the multilib file can mark a library as depending on
30+
any set of by matching multiple options. The "armvX" architecture version isn't
31+
a valid option, but that doesn't matter to multilib, and means that we don't
32+
need to repeat the matching for every minor version.
33+
34+
For architecture versions, we expand -march=armvX.Y-a+features to include every
35+
lower or equal architecture version, so that if, for example, a library
36+
requires armv8.3-a, then a link command targeting any later version will be
37+
able to select it. These generated options don't include the feature modifiers,
38+
which can be matched separately if a library requires them.
2439
"""
2540

2641
import argparse
2742
import json
2843
import os
2944
import shlex
3045
import subprocess
46+
from dataclasses import dataclass
3147

3248

3349
def get_fpu_list(args):
@@ -164,21 +180,7 @@ def get_target_features(args, fpu):
164180
return features
165181

166182

167-
def main():
168-
parser = argparse.ArgumentParser(
169-
description=__doc__,
170-
formatter_class=argparse.RawDescriptionHelpFormatter,
171-
)
172-
parser.add_argument(
173-
"--clang", required=True, help="Path to clang executable."
174-
)
175-
parser.add_argument(
176-
"--llvm-source",
177-
required=True,
178-
help="Path to root of llvm-project source tree.",
179-
)
180-
args = parser.parse_args()
181-
183+
def generate_fpus(args):
182184
# Collect all the data: make the list of FPU names, and the set of
183185
# features that LLVM maps each one to.
184186
fpu_features = {
@@ -208,7 +210,109 @@ def main():
208210
print(" Flags:")
209211
for sub_fpu in subsets:
210212
print(" - -mfpu=" + sub_fpu)
213+
print()
214+
215+
216+
def get_extension_list(clang, triple):
217+
"""Extract the list of architecture extension flags from clang, by running
218+
it with the --print-supported-extensions option."""
219+
220+
command = [
221+
clang,
222+
"--target=" + triple,
223+
"--print-supported-extensions",
224+
]
225+
226+
output = subprocess.check_output(
227+
command, stderr=subprocess.STDOUT
228+
).decode()
229+
230+
for line in output.split("\n"):
231+
parts = line.split(maxsplit=1)
232+
# The feature lines will look like this, ignore everything else:
233+
# aes FEAT_AES, FEAT_PMULL Enable AES support
234+
if len(parts) == 2 and parts[1].startswith("FEAT_"):
235+
yield parts[0]
236+
237+
238+
def generate_extensions(args):
239+
aarch64_features = get_extension_list(args.clang, "aarch64-none-eabi")
240+
aarch32_features = get_extension_list(args.clang, "arm-none-eabi")
241+
all_features = set(aarch64_features) | set(aarch32_features)
242+
243+
print("# Expand -march=...+[no]feature... into individual options we can match")
244+
print("# on. We use 'armvX' to represent a feature applied to any architecture, so")
245+
print("# that these don't need to be repeated for every version. Libraries which")
246+
print("# require a particular architecture version or profile should also match on the")
247+
print("# original option to check that.")
248+
249+
for feature in all_features:
250+
print(f"- Match: -march=armv.*\\+{feature}($|\+.*)")
251+
print(f" Flags:")
252+
print(f" - -march=armvX+{feature}")
253+
print(f"- Match: -march=armv.*\\+no{feature}($|\+.*)")
254+
print(f" Flags:")
255+
print(f" - -march=armvX+no{feature}")
256+
print()
257+
258+
259+
@dataclass
260+
class Version:
261+
major: int
262+
minor: int
263+
profile: int
264+
265+
def __str__(self):
266+
if self.minor == 0:
267+
return f"armv{self.major}-{self.profile}"
268+
else:
269+
return f"armv{self.major}.{self.minor}-{self.profile}"
270+
271+
@property
272+
def all_compatible(self):
273+
yield self
274+
for compat_minor in range(self.minor):
275+
yield Version(self.major, compat_minor, self.profile)
276+
if self.major == 9:
277+
for compat_minor in range(self.minor + 5 + 1):
278+
yield Version(self.major - 1, compat_minor, self.profile)
279+
280+
def generate_versions(args):
281+
"""Generate match blocks which allow selecting a library build for a
282+
lower-version architecture, for the v8.x-A and v9.x-A minor versions."""
283+
versions = (
284+
[Version(8, minor, "a") for minor in range(10)] +
285+
[Version(9, minor, "a") for minor in range(6)] +
286+
[Version(8, minor, "r") for minor in range(1)]
287+
)
288+
289+
for match_ver in versions:
290+
print(f"- Match: -march={match_ver}.*")
291+
print(f" Flags:")
292+
for compat_ver in match_ver.all_compatible:
293+
print(f" - -march={compat_ver}")
294+
print()
295+
296+
297+
298+
def main():
299+
parser = argparse.ArgumentParser(
300+
description=__doc__,
301+
formatter_class=argparse.RawDescriptionHelpFormatter,
302+
)
303+
parser.add_argument(
304+
"--clang", required=True, help="Path to clang executable."
305+
)
306+
parser.add_argument(
307+
"--llvm-source",
308+
required=True,
309+
help="Path to root of llvm-project source tree.",
310+
)
311+
args = parser.parse_args()
211312

313+
generate_fpus(args)
314+
generate_extensions(args)
315+
generate_versions(args)
212316

213317
if __name__ == "__main__":
214318
main()

test/multilib/aarch64.test

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
1-
# RUN: %clang -print-multi-directory --target=aarch64-none-elf | FileCheck %s
2-
# CHECK: aarch64-none-elf/aarch64a_exn_rtti{{$}}
3-
# CHECK-EMPTY:
1+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf | FileCheck %s --check-prefix=AARCH64-EXNRTTI
2+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8-a | FileCheck %s --check-prefix=AARCH64-EXNRTTI
3+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8-a+fp16 | FileCheck %s --check-prefix=AARCH64-EXNRTTI
4+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8.1-a | FileCheck %s --check-prefix=AARCH64-EXNRTTI
5+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8.5-a+nodotprod | FileCheck %s --check-prefix=AARCH64-EXNRTTI
6+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8.9-a | FileCheck %s --check-prefix=AARCH64-EXNRTTI
7+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv9.5-a | FileCheck %s --check-prefix=AARCH64-EXNRTTI
8+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv9.5-a+sve2+sme2 | FileCheck %s --check-prefix=AARCH64-EXNRTTI
9+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -mcpu=cortex-a57 | FileCheck %s --check-prefix=AARCH64-EXNRTTI
10+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -mcpu=cortex-a57+fp16 | FileCheck %s --check-prefix=AARCH64-EXNRTTI
11+
12+
# AARCH64-EXNRTTI: aarch64-none-elf/aarch64a_exn_rtti{{$}}
13+
# AARCH64-EXNRTTI-EMPTY:
14+
#
15+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -fno-exceptions -fno-rtti | FileCheck %s --check-prefix=AARCH64
16+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv8.5-a+nodotprod -fno-exceptions -fno-rtti | FileCheck %s --check-prefix=AARCH64
17+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -march=armv9.5-a+sve2+sme2 -fno-exceptions -fno-rtti | FileCheck %s --check-prefix=AARCH64
18+
# RUN: %clang -print-multi-directory --target=aarch64-none-elf -mcpu=cortex-a57+fp16 -fno-exceptions -fno-rtti | FileCheck %s --check-prefix=AARCH64
19+
#
20+
# AARCH64: aarch64-none-elf/aarch64a{{$}}
21+
# AARCH64-EMPTY:

test/multilib/armv8a.test

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none | FileCheck %s
22
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none -marm | FileCheck %s
33
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none -mthumb | FileCheck %s
4+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none -march=armv9.5-a | FileCheck %s
5+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none -march=armv8.2-a+fp16 | FileCheck %s
6+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabi -mfpu=none -march=armv8.5-a+nodotprod | FileCheck %s
47
# CHECK: arm-none-eabi/armv7a_soft_nofp_exn_rtti{{$}}
58
# CHECK-EMPTY:
69

@@ -15,5 +18,8 @@
1518
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=neon-vfpv4 | FileCheck --check-prefix=VFPV3 %s
1619
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=vfpv3-d16 -marm | FileCheck --check-prefix=VFPV3 %s
1720
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=vfpv3-d16 -mthumb | FileCheck --check-prefix=VFPV3 %s
21+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=fp-armv8 -march=armv9.5-a | FileCheck --check-prefix=VFPV3 %s
22+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=fp-armv8 -march=armv8.2-a+fp16 | FileCheck --check-prefix=VFPV3 %s
23+
# RUN: %clang -print-multi-directory --target=armv8a-none-eabihf -mfpu=fp-armv8 -march=armv8.5-a+nodotprod | FileCheck --check-prefix=VFPV3 %s
1824
# VFPV3: arm-none-eabi/armv7a_hard_vfpv3_d16_exn_rtti{{$}}
1925
# VFPV3-EMPTY:

test/multilib/armv8r.test

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# RUN: %clang -print-multi-directory --target=armv8r-none-eabi -mfpu=none | FileCheck %s
22
# RUN: %clang -print-multi-directory --target=armv8r-none-eabi -mfpu=none -marm | FileCheck %s
33
# RUN: %clang -print-multi-directory --target=armv8r-none-eabi -mfpu=none -mthumb | FileCheck %s
4+
# RUN: %clang -print-multi-directory --target=armv8r-none-eabi -mfpu=none -march=armv8-r+ras | FileCheck %s
5+
# RUN: %clang -print-multi-directory --target=armv8r-none-eabi -mfpu=none -mcpu=cortex-r52 | FileCheck %s
46
# CHECK: arm-none-eabi/armv7r_soft_nofp_exn_rtti{{$}}
57
# CHECK-EMPTY:
68

@@ -15,5 +17,6 @@
1517
# RUN: %clang -print-multi-directory --target=armv8r-none-eabihf -mfpu=neon-vfpv4 | FileCheck --check-prefix=VFPV3 %s
1618
# RUN: %clang -print-multi-directory --target=armv8r-none-eabihf -mfpu=vfpv3-d16 -marm | FileCheck --check-prefix=VFPV3 %s
1719
# RUN: %clang -print-multi-directory --target=armv8r-none-eabihf -mfpu=vfpv3-d16 -mthumb | FileCheck --check-prefix=VFPV3 %s
20+
# RUN: %clang -print-multi-directory --target=armv8r-none-eabihf -mcpu=cortex-r52 | FileCheck --check-prefix=VFPV3 %s
1821
# VFPV3: arm-none-eabi/armv7r_hard_vfpv3_d16_exn_rtti{{$}}
1922
# VFPV3-EMPTY:

0 commit comments

Comments
 (0)