[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.
This commit is contained in:
Roland McGrath
2025-02-14 12:54:46 -08:00
committed by GitHub
parent 778001514f
commit aa500a79fc
6 changed files with 103 additions and 24 deletions

View File

@@ -6,25 +6,68 @@
#
# ==-------------------------------------------------------------------------==#
import re
from type import Type
# These are the keywords that appear in C type syntax but are not part of the
# include file name. This is all of the modifiers, qualifiers, and base types,
# but not "struct".
KEYWORDS = [
"_Atomic",
"_Complex",
"_Float16",
"_Noreturn",
"__restrict",
"accum",
"char",
"const",
"double",
"float",
"fract",
"int",
"long",
"short",
"signed",
"unsigned",
"void",
"volatile",
]
NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+")
class Function:
def __init__(
self, return_type, name, arguments, standards, guard=None, attributes=[]
):
assert return_type
self.return_type = return_type
self.name = name
self.arguments = [
arg if isinstance(arg, str) else arg["type"] for arg in arguments
]
assert all(self.arguments)
self.standards = standards
self.guard = guard
self.attributes = attributes or ""
self.attributes = attributes or []
def signature_types(self):
def collapse(type_string):
assert type_string
# Split into words at nonidentifier characters (`*`, `[`, etc.),
# filter out keywords and numbers, and then rejoin with "_".
return "_".join(
word
for word in NONIDENTIFIER.split(type_string)
if word and not word.isdecimal() and word not in KEYWORDS
)
all_types = [self.return_type] + self.arguments
return {
Type(string) for string in filter(None, (collapse(t) for t in all_types))
}
def __str__(self):
attributes_str = " ".join(self.attributes)
attrs_str = "".join(f"{attr} " for attr in self.attributes)
arguments_str = ", ".join(self.arguments) if self.arguments else "void"
if attributes_str == "":
result = f"{self.return_type} {self.name}({arguments_str})"
else:
result = f"{attributes_str} {self.return_type} {self.name}({arguments_str})"
return result
return attrs_str + f"{self.return_type} {self.name}({arguments_str})"

View File

@@ -6,9 +6,33 @@
#
# ==-------------------------------------------------------------------------==#
from functools import reduce
from pathlib import PurePosixPath
STDINT_SIZES = [
"16",
"32",
"64",
"8",
"least16",
"least32",
"least64",
"least8",
"max",
"ptr",
]
COMPILER_HEADER_TYPES = (
{
"bool": "<stdbool.h>",
"va_list": "<stdarg.h>",
}
| {f"int{size}_t": "<stdint.h>" for size in STDINT_SIZES}
| {f"uint{size}_t": "<stdint.h>" for size in STDINT_SIZES}
)
class HeaderFile:
def __init__(self, name):
self.template_file = None
@@ -34,19 +58,25 @@ class HeaderFile:
def add_function(self, function):
self.functions.append(function)
def includes(self):
return sorted(
{
PurePosixPath("llvm-libc-macros") / macro.header
for macro in self.macros
if macro.header is not None
}
| {
PurePosixPath("llvm-libc-types") / f"{typ.type_name}.h"
for typ in self.types
}
def all_types(self):
return reduce(
lambda a, b: a | b,
[f.signature_types() for f in self.functions],
set(self.types),
)
def includes(self):
return {
PurePosixPath("llvm-libc-macros") / macro.header
for macro in self.macros
if macro.header is not None
} | {
COMPILER_HEADER_TYPES.get(
typ.type_name, PurePosixPath("llvm-libc-types") / f"{typ.type_name}.h"
)
for typ in self.all_types()
}
def public_api(self):
# Python 3.12 has .relative_to(dir, walk_up=True) for this.
path_prefix = PurePosixPath("../" * (len(PurePosixPath(self.name).parents) - 1))
@@ -56,7 +86,10 @@ class HeaderFile:
content = [
f"#include {file}"
for file in sorted(f'"{relpath(file)!s}"' for file in self.includes())
for file in sorted(
file if isinstance(file, str) else f'"{relpath(file)!s}"'
for file in self.includes()
)
]
for macro in self.macros:

View File

@@ -11,10 +11,10 @@
#include "__llvm-libc-common.h"
#include "llvm-libc-macros/float16-macros.h"
#include "llvm-libc-types/float128.h"
#include "llvm-libc-macros/test_more-macros.h"
#include "llvm-libc-macros/test_small-macros.h"
#include "llvm-libc-types/float128.h"
#include "llvm-libc-types/type_a.h"
#include "llvm-libc-types/type_b.h"

View File

@@ -1,8 +1,5 @@
header: subdir/test.h
header_template: test.h.def
types:
- type_name: type_a
- type_name: type_b
functions:
- name: func
return_type: type_a

View File

@@ -11,7 +11,6 @@
#include "__llvm-libc-common.h"
#include "llvm-libc-macros/float16-macros.h"
#include "llvm-libc-types/float128.h"
%%public_api()

View File

@@ -9,4 +9,11 @@
class Type:
def __init__(self, type_name):
assert type_name
self.type_name = type_name
def __eq__(self, other):
return self.type_name == other.type_name
def __hash__(self):
return self.type_name.__hash__()