Skip to content

Commit aa500a7

Browse files
authored
[libc] Make hdrgen deduce header type lists from function signatures (#127251)
With this, the `types` list in YAML files should only be used to list the types that a standard specifies should be in that header per se. All the types referenced in function signatures will be collected automatically.
1 parent 7780015 commit aa500a7

File tree

6 files changed

+103
-24
lines changed

6 files changed

+103
-24
lines changed

libc/utils/hdrgen/function.py

Lines changed: 50 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,68 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
import re
10+
from type import Type
11+
12+
13+
# These are the keywords that appear in C type syntax but are not part of the
14+
# include file name. This is all of the modifiers, qualifiers, and base types,
15+
# but not "struct".
16+
KEYWORDS = [
17+
"_Atomic",
18+
"_Complex",
19+
"_Float16",
20+
"_Noreturn",
21+
"__restrict",
22+
"accum",
23+
"char",
24+
"const",
25+
"double",
26+
"float",
27+
"fract",
28+
"int",
29+
"long",
30+
"short",
31+
"signed",
32+
"unsigned",
33+
"void",
34+
"volatile",
35+
]
36+
NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+")
37+
938

1039
class Function:
1140
def __init__(
1241
self, return_type, name, arguments, standards, guard=None, attributes=[]
1342
):
43+
assert return_type
1444
self.return_type = return_type
1545
self.name = name
1646
self.arguments = [
1747
arg if isinstance(arg, str) else arg["type"] for arg in arguments
1848
]
49+
assert all(self.arguments)
1950
self.standards = standards
2051
self.guard = guard
21-
self.attributes = attributes or ""
52+
self.attributes = attributes or []
53+
54+
def signature_types(self):
55+
def collapse(type_string):
56+
assert type_string
57+
# Split into words at nonidentifier characters (`*`, `[`, etc.),
58+
# filter out keywords and numbers, and then rejoin with "_".
59+
return "_".join(
60+
word
61+
for word in NONIDENTIFIER.split(type_string)
62+
if word and not word.isdecimal() and word not in KEYWORDS
63+
)
64+
65+
all_types = [self.return_type] + self.arguments
66+
return {
67+
Type(string) for string in filter(None, (collapse(t) for t in all_types))
68+
}
2269

2370
def __str__(self):
24-
attributes_str = " ".join(self.attributes)
71+
attrs_str = "".join(f"{attr} " for attr in self.attributes)
2572
arguments_str = ", ".join(self.arguments) if self.arguments else "void"
26-
if attributes_str == "":
27-
result = f"{self.return_type} {self.name}({arguments_str})"
28-
else:
29-
result = f"{attributes_str} {self.return_type} {self.name}({arguments_str})"
30-
return result
73+
return attrs_str + f"{self.return_type} {self.name}({arguments_str})"

libc/utils/hdrgen/header.py

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,33 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
from functools import reduce
910
from pathlib import PurePosixPath
1011

1112

13+
STDINT_SIZES = [
14+
"16",
15+
"32",
16+
"64",
17+
"8",
18+
"least16",
19+
"least32",
20+
"least64",
21+
"least8",
22+
"max",
23+
"ptr",
24+
]
25+
26+
COMPILER_HEADER_TYPES = (
27+
{
28+
"bool": "<stdbool.h>",
29+
"va_list": "<stdarg.h>",
30+
}
31+
| {f"int{size}_t": "<stdint.h>" for size in STDINT_SIZES}
32+
| {f"uint{size}_t": "<stdint.h>" for size in STDINT_SIZES}
33+
)
34+
35+
1236
class HeaderFile:
1337
def __init__(self, name):
1438
self.template_file = None
@@ -34,19 +58,25 @@ def add_object(self, object):
3458
def add_function(self, function):
3559
self.functions.append(function)
3660

37-
def includes(self):
38-
return sorted(
39-
{
40-
PurePosixPath("llvm-libc-macros") / macro.header
41-
for macro in self.macros
42-
if macro.header is not None
43-
}
44-
| {
45-
PurePosixPath("llvm-libc-types") / f"{typ.type_name}.h"
46-
for typ in self.types
47-
}
61+
def all_types(self):
62+
return reduce(
63+
lambda a, b: a | b,
64+
[f.signature_types() for f in self.functions],
65+
set(self.types),
4866
)
4967

68+
def includes(self):
69+
return {
70+
PurePosixPath("llvm-libc-macros") / macro.header
71+
for macro in self.macros
72+
if macro.header is not None
73+
} | {
74+
COMPILER_HEADER_TYPES.get(
75+
typ.type_name, PurePosixPath("llvm-libc-types") / f"{typ.type_name}.h"
76+
)
77+
for typ in self.all_types()
78+
}
79+
5080
def public_api(self):
5181
# Python 3.12 has .relative_to(dir, walk_up=True) for this.
5282
path_prefix = PurePosixPath("../" * (len(PurePosixPath(self.name).parents) - 1))
@@ -56,7 +86,10 @@ def relpath(file):
5686

5787
content = [
5888
f"#include {file}"
59-
for file in sorted(f'"{relpath(file)!s}"' for file in self.includes())
89+
for file in sorted(
90+
file if isinstance(file, str) else f'"{relpath(file)!s}"'
91+
for file in self.includes()
92+
)
6093
]
6194

6295
for macro in self.macros:

libc/utils/hdrgen/tests/expected_output/test_header.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
#include "__llvm-libc-common.h"
1313
#include "llvm-libc-macros/float16-macros.h"
14-
#include "llvm-libc-types/float128.h"
1514

1615
#include "llvm-libc-macros/test_more-macros.h"
1716
#include "llvm-libc-macros/test_small-macros.h"
17+
#include "llvm-libc-types/float128.h"
1818
#include "llvm-libc-types/type_a.h"
1919
#include "llvm-libc-types/type_b.h"
2020

libc/utils/hdrgen/tests/input/subdir/test.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
header: subdir/test.h
22
header_template: test.h.def
3-
types:
4-
- type_name: type_a
5-
- type_name: type_b
63
functions:
74
- name: func
85
return_type: type_a

libc/utils/hdrgen/tests/input/test_small.h.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
#include "__llvm-libc-common.h"
1313
#include "llvm-libc-macros/float16-macros.h"
14-
#include "llvm-libc-types/float128.h"
1514

1615
%%public_api()
1716

libc/utils/hdrgen/type.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,11 @@
99

1010
class Type:
1111
def __init__(self, type_name):
12+
assert type_name
1213
self.type_name = type_name
14+
15+
def __eq__(self, other):
16+
return self.type_name == other.type_name
17+
18+
def __hash__(self):
19+
return self.type_name.__hash__()

0 commit comments

Comments
 (0)