Skip to content

Conversation

danbrown-amd
Copy link
Contributor

@danbrown-amd danbrown-amd commented May 8, 2025

Fixes #3092

Copy link
Contributor

github-actions bot commented May 8, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@danbrown-amd danbrown-amd force-pushed the attr-arg-consts branch 3 times, most recently from 9db3b6c to 243acbc Compare May 13, 2025 22:08
Copy link
Collaborator

@s-perron s-perron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind this change generally. It will be good for SPIR-V.

I don't know if this is complete yet (it is still a draft). I pointed out one issue with using LocalSize. You might also need to look at SpirvEmitter::addDerivativeGroupExecutionMode(). That function determines which derivative group execution mode to add based on the number of threas in the group. However, if you have a spec constant for the number of threads, we cannot do that.

@danbrown-amd danbrown-amd force-pushed the attr-arg-consts branch 2 times, most recently from 58352af to 357813d Compare June 12, 2025 02:30
@danbrown-amd
Copy link
Contributor Author

danbrown-amd commented Jun 17, 2025

Why was SpirvEmitter::addDerivativeGroupExecutionMode() written that way? It seems to me that it wouldn't be that difficult to provide enough context to find the original attribute in the AST so the method wouldn't need to scan the previously emitted instructions.

Of course, since there's no access to specializations at compile time, there's no way to ensure the best choice of execution mode with spec constants anyway. However, in some cases partial information would be sufficient to rule out one of them. If both are possible, maybe pick one and issue a warning?

@danbrown-amd danbrown-amd marked this pull request as ready for review June 19, 2025 18:27
@danbrown-amd danbrown-amd changed the title Allows defined constants as attribute arguments. Allows Vulkan spec constants as attribute arguments. Jun 26, 2025
@s-perron
Copy link
Collaborator

s-perron commented Jul 7, 2025

Why was SpirvEmitter::addDerivativeGroupExecutionMode() written that way?

It was implemented that way because that was the HLSL spec implemented for DXIL. See Thread Groups and Quads. I don't mind if we diverge from it when there are specialization constants. We just need to document it.

If both are possible, maybe pick one and issue a warning?

That is a reasonable idea. Longer term, we could try to add explicit attribute that apply to the entry point that would override the guess.

Copy link
Collaborator

@s-perron s-perron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but requires some tests.

Also restores file inadvertently committed source file changed for debugging.
@s-perron s-perron requested a review from llvm-beanz July 11, 2025 17:48
Copy link
Collaborator

@llvm-beanz llvm-beanz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a lot of missing test coverage here. You're making a bunch of attributes that had previously either required integer literal arguments or optional integer literal arguments now support constant expressions and specialization constants.

We really need test coverage for each attribute's change in behavior, and the error states. In particular it doesn't seem to me like you're actually handling the possible error of a non-constant expression being provided as a value. I think it just silently replaces the value with the default (which would be bad).

@@ -328,6 +328,19 @@ class CGMSHLSLRuntime : public CGHLSLRuntime {
};
} // namespace

static uint32_t GetIntConstAttrArg(ASTContext &astContext, const Expr *expr,
uint32_t defaultVal = 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
uint32_t defaultVal = 0) {
uint32_t defaultVal) {

Doesn't look like this is ever called without a default value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed this to use llvm::Optional so that an absent default indicates that expr should be non-null. (See note on SemaHLSL below.)

const uint NumThreadsY = 1;
#endif

[numthreads(NumThreadsX,NumThreadsY,1)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some other test cases that are probably interesting:

uint CBufferValue;
[numthreads(CbufferValue, 1, 1)] // Should error
void main() {} 
const uint Eight = 8;
[numthreads(Eight * 2, Eight, 1)] // Should work
void main() {} 

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The latter won't work but would if declared static. Larger expressions incorporating spec constants don't work in the current version.

I've added preprocessor directives to vk.spec-constants.attributes.hlsl to enable removal of the spec constant designations to test for expected errors.

Comment on lines 12286 to 12287
static uint32_t GetIntConstAttrArg(ASTContext &astContext, const Expr *expr,
uint32_t defaultVal = 0) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static uint32_t GetIntConstAttrArg(ASTContext &astContext, const Expr *expr,
uint32_t defaultVal = 0) {
static uint32_t GetIntConstAttrArg(ASTContext &astContext, const Expr *expr,
uint32_t defaultVal) {

It is really unfortunate to completely duplicate this code, and I don't think the two should be identical. In this version in Sema we should be surfacing an error if there is an expression that isn't a constant expression or spec constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sema already seems to complain in all the relevant cases, though I have added some more diagnostics. Of the arguments allowed to be spec constants, the only optional one is the NodeId index, so maybe just return zero (possibly after issuing an error) whenever expr is null? For now the function works as described for the CGHLSLMS version.

return (uint32_t)apsInt.getSExtValue();
if (expr->isVulkanSpecConstantExpr(astContext, &apValue) && apValue.isInt())
return (uint32_t)apValue.getInt().getSExtValue();
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
llvm_unreachable("Expression must be a constant expression or spec constant")
}

We should be erroring in Sema if this isn't a constant expression or spec constant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed as suggested.

@@ -328,6 +328,19 @@ class CGMSHLSLRuntime : public CGHLSLRuntime {
};
} // namespace

static uint32_t GetIntConstAttrArg(ASTContext &astContext, const Expr *expr,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You've got a fair amount of mixing coding style, and DXC is a bit inconsistent.

In general if you're adding code in a part of the codebase that isn't otherwise following a consistent style we follow the LLVM Coding Standards. LLVM uses CamelCase for variable names and type names (see: https://llvm.org/docs/CodingStandards.html#name-types-functions-variables-and-enumerators-properly).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: New
Development

Successfully merging this pull request may close these issues.

[SPIR-V] Allow thread group size to be specified with specialization constants
3 participants