-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[AMDGPU][clang][CodeGen][opt] Add late-resolved feature identifying predicates #134016
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
91eeaf0
8bf1168
3421292
539c7e6
5926b9f
4381d93
d18f64e
7880ff4
719dfde
36b69b4
e327e15
d35efc5
5dee670
888a080
e35ac62
6c41ed2
8683148
a9b3e85
468a517
1b8b57e
18b4af2
a8bca2f
716cc1f
79035a9
6945c2e
9a7e250
0f04dbc
39a9d55
3fe116e
49c862a
f293f39
251476d
ebde49b
4bdd30e
a1b4a11
18841c1
76848d5
e1bfdf3
4f65468
e940d42
46adb74
ca9521d
11dd570
fab0d14
611ec0d
03b029f
32be1c0
012f74d
cd7c920
33bbe35
46e5a91
8c1e1f5
81a55d8
bbe17fa
c495630
420a19c
dc0221e
7f88eb7
3b727b9
42f5de6
246ff38
adb6469
6b368d5
435ce05
2c2f78b
09115e2
f1d41a8
5d2c2f6
05033ea
b886c55
63d059d
495b567
8ef5c70
8177876
b4decc2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4920,6 +4920,116 @@ If no address spaces names are provided, all address spaces are fenced. | |
__builtin_amdgcn_fence(__ATOMIC_SEQ_CST, "workgroup", "local") | ||
__builtin_amdgcn_fence(__ATOMIC_SEQ_CST, "workgroup", "local", "global") | ||
|
||
__builtin_amdgcn_processor_is and __builtin_amdgcn_is_invocable | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
``__builtin_amdgcn_processor_is`` and ``__builtin_amdgcn_is_invocable`` provide | ||
a functional mechanism for programatically querying: | ||
|
||
* the identity of the current target processor; | ||
* the capability of the current target processor to invoke a particular builtin. | ||
|
||
**Syntax**: | ||
|
||
.. code-block:: c | ||
|
||
// When used as the predicate for a control structure | ||
bool __builtin_amdgcn_processor_is(const char*); | ||
bool __builtin_amdgcn_is_invocable(builtin_name); | ||
// Otherwise | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there a use case for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there an use case for the “Otherwise” scenario? No, it merely ensures that other uses are broken since there’s no void-to-anything conversion possible. Apologies if you are asking a different question and I misunderstood. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean as "as the predicate for a control structure" here for there to be an otherwise. Why not just make this a diagnostic? OR have a reasonable value in those cases? Also, having the argument type change as well as the return value for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Re-answering my own question: Later on you seem to be using 'predicate for a control structure' to mean 'the condition of a if/while/for. However, why is it problematic to have someone check this and store it in a variable? Why is:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what is the type in an unevaluated context? So what is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Type, when "observable", is always There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about when that context is inside of an Either way, I'm pretty against the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'm not comfortable with a signature that changes depending on context. That's a pretty novel design. |
||
void __builtin_amdgcn_processor_is(const char*); | ||
void __builtin_amdgcn_is_invocable(void); | ||
|
||
**Example of use**: | ||
|
||
.. code-block:: c++ | ||
|
||
if (__builtin_amdgcn_processor_is("gfx1201") || | ||
__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var)) | ||
__builtin_amdgcn_s_sleep_var(x); | ||
|
||
if (!__builtin_amdgcn_processor_is("gfx906")) | ||
__builtin_amdgcn_s_wait_event_export_ready(); | ||
else if (__builtin_amdgcn_processor_is("gfx1010") || | ||
__builtin_amdgcn_processor_is("gfx1101")) | ||
__builtin_amdgcn_s_ttracedata_imm(1); | ||
|
||
while (__builtin_amdgcn_processor_is("gfx1101")) *p += x; | ||
|
||
do { *p -= x; } while (__builtin_amdgcn_processor_is("gfx1010")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is the formatting OK on this line? Github is making this look awful weird. Also-also: This is an infinite loop, right? As you said this is never evaluated at runtime, the answer would be fixed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This would indeed be an infinite loop iff the concrete target is |
||
|
||
for (; __builtin_amdgcn_processor_is("gfx1201"); ++*p) break; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question about inf. loop here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this'd be an infinite loop ever, it's either 0 trips or one trip, if the predicate is true we just |
||
|
||
if (__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_wait_event_export_ready)) | ||
__builtin_amdgcn_s_wait_event_export_ready(); | ||
else if (__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_ttracedata_imm)) | ||
__builtin_amdgcn_s_ttracedata_imm(1); | ||
|
||
do { | ||
*p -= x; | ||
} while (__builtin_amdgcn_is_invocable(__builtin_amdgcn_global_load_tr_b64_i32)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Formatting on this one is weird too. Also, same question again, and again on 4972. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please see my previous replies, hopefully they clarify matters. |
||
|
||
for (; __builtin_amdgcn_is_invocable(__builtin_amdgcn_permlane64); ++*p) break; | ||
|
||
**Description**: | ||
|
||
When used as the predicate value of the following control structures: | ||
|
||
.. code-block:: c++ | ||
|
||
if (...) | ||
while (...) | ||
do { } while (...) | ||
for (...) | ||
|
||
be it directly, or as arguments to logical operators such as ``!, ||, &&``, the | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about when used as an initializer in one of those? Consider:
|
||
builtins return a boolean value that: | ||
|
||
* indicates whether the current target matches the argument; the argument MUST | ||
be a string literal and a valid AMDGPU target | ||
* indicates whether the builtin function passed as the argument can be invoked | ||
by the current target; the argument MUST be either a generic or AMDGPU | ||
specific builtin name | ||
|
||
Outside of these contexts, the builtins have a ``void`` returning signature | ||
which prevents their misuse. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What misuse here? If you want to catch other situations, just diagnose. But it seems that these values could be useful/possible outside of condition expressions. |
||
|
||
**Example of invalid use**: | ||
|
||
.. code-block:: c++ | ||
|
||
void kernel(int* p, int x, bool (*pfn)(bool), const char* str) { | ||
if (__builtin_amdgcn_processor_is("not_an_amdgcn_gfx_id")) return; | ||
else if (__builtin_amdgcn_processor_is(str)) __builtin_trap(); | ||
|
||
bool a = __builtin_amdgcn_processor_is("gfx906"); | ||
const bool b = !__builtin_amdgcn_processor_is("gfx906"); | ||
const bool c = !__builtin_amdgcn_processor_is("gfx906"); | ||
bool d = __builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); | ||
bool e = !__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); | ||
const auto f = | ||
!__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_wait_event_export_ready) | ||
|| __builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); | ||
const auto g = | ||
!__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_wait_event_export_ready) | ||
|| !__builtin_amdgcn_is_invocable(__builtin_amdgcn_s_sleep_var); | ||
__builtin_amdgcn_processor_is("gfx1201") | ||
? __builtin_amdgcn_s_sleep_var(x) : __builtin_amdgcn_s_sleep(42); | ||
if (pfn(__builtin_amdgcn_processor_is("gfx1200"))) | ||
__builtin_amdgcn_s_sleep_var(x); | ||
|
||
if (__builtin_amdgcn_is_invocable("__builtin_amdgcn_s_sleep_var")) return; | ||
else if (__builtin_amdgcn_is_invocable(x)) __builtin_trap(); | ||
} | ||
|
||
When invoked while compiling for a concrete target, the builtins are evaluated | ||
early by Clang, and never produce any CodeGen effects / have no observable | ||
side-effects in IR. Conversely, when compiling for AMDGCN flavoured SPIR-v, | ||
which is an abstract target, a series of predicate values are implicitly | ||
created. These predicates get resolved when finalizing the compilation process | ||
for a concrete target, and shall reflect the latter's identity and features. | ||
Thus, it is possible to author high-level code, in e.g. HIP, that is target | ||
adaptive in a dynamic fashion, contrary to macro based mechanisms. | ||
|
||
ARM/AArch64 Language Extensions | ||
------------------------------- | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC @sarnex @jhuber6 as this relates to
__has_builtin
behavior somewhat and we've been in discussions about whether that should mean "I know about the builtin" or "I can actually call the builtin".