This is an archive of the discontinued LLVM Phabricator instance.

[clang] Add __has_target_feature
Needs ReviewPublic

Authored by yaxunl on May 13 2022, 9:07 AM.

Details

Summary

Depending on whether a target feature is enabled or not,
programs may choose different algorithm or different
builtin functions to use.

Instead of let each target to emit predefined macros
for specific target feature, this patch introduce a
function-like builtin macro __has_target_feature.

Diff Detail

Event Timeline

yaxunl created this revision.May 13 2022, 9:07 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 13 2022, 9:07 AM
yaxunl requested review of this revision.May 13 2022, 9:07 AM
yaxunl updated this revision to Diff 429265.May 13 2022, 9:12 AM

fix typo

tra added inline comments.May 13 2022, 9:53 AM
clang/docs/LanguageExtensions.rst
275

Do you have a better example? This particular case could've been handled by existing __has_builtin().

While I could see usefulness of checking features (e.g. for CUDA/NVPTX it could be used to chose inline assembly supported only by newer PTX versions, but even then that choice could be made using existing methods, even if they are not always direct (e.g. by using CUDA_VERSION as a proxy for "new enough PTX version").

yaxunl marked an inline comment as done.May 13 2022, 10:21 AM
yaxunl added inline comments.
clang/docs/LanguageExtensions.rst
275

__has_builtin returns 1 as long as the builtin is known to clang, even if the builtin is not supported by the target CPU. This is because the required target feature for a builtin is in ASTContext, whereas __has_builtin is evaluated in preprocessor, where the information is not known.

It's not clear to me why existing facilities shouldn't be extended to cover this case rather than coming up with another feature testing macro. There's already plenty of confusion for users to decide between __has_feature and __has_extension, and now we're talking about adding a third choice to the mix.

clang/docs/LanguageExtensions.rst
260

The first question that comes to mind for me is: why is __has_feature not sufficient?

275

__has_builtin returns 1 as long as the builtin is known to clang, even if the builtin is not supported by the target CPU. This is because the required target feature for a builtin is in ASTContext, whereas __has_builtin is evaluated in preprocessor, where the information is not known.

Why is that not a deficiency with __has_builtin that we should fix?

yaxunl marked 2 inline comments as done.May 16 2022, 7:43 AM
yaxunl added inline comments.
clang/docs/LanguageExtensions.rst
260

__has_target_feature accepts predefined target features for the specified target triple and CPU. The names of target features are determined by the target. They may overlap with clang features and cause ambiguity. Another issue is that they usually contain '-', which makes them not valid identifiers of C/C++, therefore the builtin macro has to accept a string literal argument instead of identifier argument like __has_feature.

275

It is arguable whether this is a bug for __has_builtin. I tend to treat it as a bug and think it should be fixed. However, fixing it may cause regressions since there may be existing code expecting __has_builtin not depending on availability of required target feature. This will limit the usability of a fix for this issue.

Even if we agree that this is a bug for __has_builtin which should be fixed, this does conflict with adding __has_target_feature, as __has_target_feature has more uses than determining whether a target builtin is available, e.g. choosing different algorithms based on availability of certain target feature, or using certain inline assembly code.

yaxunl marked an inline comment as done.May 16 2022, 7:47 AM
yaxunl added inline comments.
clang/docs/LanguageExtensions.rst
275

It is arguable whether this is a bug for __has_builtin. I tend to treat it as a bug and think it should be fixed. However, fixing it may cause regressions since there may be existing code expecting __has_builtin not depending on availability of required target feature. This will limit the usability of a fix for this issue.

Even if we agree that this is a bug for __has_builtin which should be fixed, this does conflict with adding __has_target_feature, as __has_target_feature has more uses than determining whether a target builtin is available, e.g. choosing different algorithms based on availability of certain target feature, or using certain inline assembly code.

sorry typo. this does not conflict

tra added a comment.May 16 2022, 10:13 AM

Oops. forgot to hit 'submit' last week, so there's some overlap with Aaron's question.

clang/docs/LanguageExtensions.rst
275

I'm missing something. __has_target_feature("s-memtime-inst") is also evaluated by preprocessor, right next to where __has_target_builtin is processed.
I guess what you're saying is that preprocessor does not pay attention to the target feature conditions attached to those builtins.
Those are evaluted in CodeGenFunction::checkTargetFeatures.

This means that in order to use __has_feature() to detect availability of target builtins would effectively require the user to specify exactly the same set of conditions, as applied to the builtin. That will work for builtins that map to features 1:1, but it will be prone to breaking for NVPTX builtins that carry fairly large set of feature requirements and that set changes every time we add a new PTX or GPU variant, which happens fairly often.

I wonder if it may be better to generalize target builtin feature evaluation and use it from both preprocessor and the codegen and just stick with __has_builtin, only now working correctly to indicate availability of the target builtins.

yaxunl marked an inline comment as done.May 17 2022, 12:19 PM
yaxunl added inline comments.
clang/docs/LanguageExtensions.rst
275

Opened https://reviews.llvm.org/D125829 to fix __has_builtin

aaron.ballman added inline comments.May 23 2022, 10:55 AM
clang/docs/LanguageExtensions.rst
260

Do we have to use a string literal? I am presuming there's an enumerated list of features for each target, and thus we can use an identifier argument (it might turn around and map that identifier back to a string literal, but that's fine). But I'm not certain I understand how a target feature will overlap with a clang feature and cause ambiguity.

My concerns really boil down to:

  • It's already hard enough for users to know when to use __has_extension vs __has_feature and this is adding another option into the mix.
  • There's no documentation about what constitutes a valid string literal for this feature and I don't know how a user would go about discovering the full enumerated list for any given target. Also, are these strings guaranteed to be stable (spelling doesn't change, strings aren't removed, etc)?
  • (much smaller concern) A string literal may not be the most user-friendly way to surface the functionality (tools typically don't auto-complete string literals or do typo correction within them).