[RFC] Support function attributes in user interface

The PoC commit is already opened at [libc][RFC] add support for function level attributes by SchrodingerZhu · Pull Request #79891 · llvm/llvm-project (github.com).

Why is this needed?

According to discussions at [libc] abs is a const function by AtariDreams · Pull Request #79650 · llvm/llvm-project (github.com), it may be helpful to annotate some functions with attributes. For example, math kernels (such as abs) generally have no side effects and are constant on the same input. Annotate them with const will effectively assist compilers to emit better code.

How is it implemented?

I hope to introduce the following in the TableGen:

class FunctionAttr {}
class GnuFunctionAttr<string attr> : FunctionAttr {
  string Attr = attr;
  string Style = "gnu";
}
class Cxx11FunctionAttr<string attr, string namespace> : FunctionAttr {
  string Attr = attr;
  string Namespace = namespace;
  string Style = "cxx11";
}
class DeclspecFunctionAttr<string attr> : FunctionAttr {
  string Attr = attr;
  string Style = "declspec";
}
class FunctionAttrSpec<string macro, list<FunctionAttr> instances> {
  list<FunctionAttr> Instances = instances;
  string Macro = macro;
}

Such that one can declare an attribute as:

FunctionAttrSpec ConstAttr = FunctionAttrSpec<"__LIBC_CONST_ATTR", [
    Cxx11FunctionAttr<"const", "gnu">,
    GnuFunctionAttr<"const">,
]>;

Then, for those applicable functions, the attribute can be added via:

FunctionSpec<"fabs", RetValSpec<DoubleType>, [ArgSpec<DoubleType>], [ConstAttr]>,

The generated header will be like:

__LIBC_CONST_ATTR double fabs(double) _NOTHROW;

Currently, the dispatch considerations are the following (in order):

  1. If __cplusplus is defined and cxx11 style is provided, define the macro using cxx11 version;
  2. Otherwise, if __GNUC__ is defined and gnu style is provided, define the macro using gnu version;
  3. (unlikely, just for future-proof) Otherwise, if _MSC_VER is defined and __declspec is provided, define the macro using __declspec version;
  4. Fallback to empty macro.

Limitations

  1. Not all attributes are supported, especially those who are sensitive to positions.
  2. Some special attributes need extra effort to define such as “quoting” the string parameter.
  3. Parameter attributes are not considered.
  4. Attributes are collected per header file, so repeated definitions are expected (Of course, all these macros are gated by macro guards and #undef at the end of the file. I just mean code duplication).

Other considerations

  1. There is an existing _Noreturn attribute which is handled in a rather “ad hoc” way (they are annotated as special return types). Perhaps we can change it to this new style if the proposal is accepted.
  2. Is #pragma push_macro("...") a better way to guard these macros?

Thanks @Lancern for mentioning the following to me:

  1. As mentioned in the commit, we may want to check the namespace of cxx11 style. Especially when we really want the MSVC version to work.
  2. c23 style is not yet considered.

Thanks for looking into this. A lot of C functions can have attributes (e.g. pure) beyond libcall recognition in the compiler, so it’s helpful. Another thing to consider is the difference between the C and C++ attributes on certain string functions like strstr std::strstr - cppreference.com.

1 Like

I have 2 questions regarding extra attributes on the function:

  • In this RPC, it is about the public headers that will be generated and used by users in the full build mode. What about the internal header that is used for internal implementation, such as in [libc] abs is a const function by AtariDreams · Pull Request #79650 · llvm/llvm-project · GitHub? Do they need to match?
  • What if the generated public headers have attributes that to not match with the system headers, shall the targets relying on these headers be restricted to full build mode only, or will need some accommodation for overlay mode also?

What about the internal header that is used for internal implementation.

Unfortunately, attributes need to be set manually for internal interfaces. I believe this is also the same for noreturn in current codebase. Internally, we know that we are using C++ and may prefer different style other than the attribute in the user interface.

What if the generated public headers have attributes that to not match with the system headers, shall the targets relying on these headers be restricted to full build mode only, or will need some accommodation for overlay mode also?

I am not exactly sure. I think currently the our headers and glibc’s headers are already different? In the sense that glibc is actually using some of these attributes?