-
Couldn't load subscription status.
- Fork 51
[xxxx] Experimental DXIL #698
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?
Conversation
proposals/xxxx-experimental-dxil.md
Outdated
| * Doesn't consume any of the current opcode space | ||
| * Obvious from reading the DXIL that experimental/extension is being used | ||
| Cons: | ||
| * Transistion from experimental to stable seems quite complicated |
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.
* Transistion from experimental to stable seems quite complicated
May be worth digging into this a bit more before we discuss it. I think the assumption here is that this transition would actually be to move to a constant op-code value. But why would we need to do that? What if the actual mechanism for making something stable is to just mark a feature ID as stable?
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.
I think the assumption here is that this transition would actually be to move to a constant op-code value.
Yep, a core assumption in the document is that "stable" opcodes should stay the same as they currently are in DXIL.
But why would we need to do that? What if the actual mechanism for making something stable is to just mark a feature ID as stable?
That's an interesting point and I have some messy thoughts below but I'll try to keep them organized :) I'll also say, this proposal is derived from something @tex3d wrote and I'm not certain I'm doing it justice.
So If I'm reading your message correctly, it sounds like we have a list of "experimental" extensions somewhere then the following
%feature_id = i32 123
%cool_operation = i32 456
%opcode = i32 dx.create.extensionop(%feature_id, %cool_operaton)
%result = i32 dx.op.binary(%opcode, %a, %b)and once the feature is no longer experimental then we remove feature ID 123 from the experimental list?
My main criticism is that we'd be "splitting" up stable opcodes. All the pre SM6.10 opcodes would use the immediate constant while all SM6.10+ stable opcodes would essentially just be extensions. Oh also, idk how much it would actually matter but this would also increase binary size over flattening them back down into an imm constant
aside: actually, writing it out this proposal is very similar to the "Single Specific Experimental Opcode" proposal below with the main difference being that you can reused %opcode in this one
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.
Yup, this is in line with what I was suggesting.
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.
Incorporated into the document! Feel free to resolve this comment if you are happy with it :)
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.
If we were willing to leave the experimental ops in a separate table, we could always do the same with the partitioned approach. Both approaches would leave behind reserved opcode slots for any opcodes deprecated during feature development.
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.
Great write up, thanks!
I've left some editorial comments and one thing that might be good to expand on, but other than that this looks like it's in pretty good shape to merge.
| solves real world use cases. Traditionally this has been done by marking all in | ||
| development opcodes as expirmental opcodes of the next dxil version release. |
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.
There has never been a way of "marking" opcodes as experimental. They are simply added at the end of the most recent released DXIL opcodes. We have an enum that defines the number of released opcodes for an indicator of which set is frozen for which DXIL version.
| solves real world use cases. Traditionally this has been done by marking all in | |
| development opcodes as expirmental opcodes of the next dxil version release. | |
| solves real world use cases. Traditionally this has been done by adding new | |
| opcodes right after the last released opcode in the prior DXIL version. |
| In most cases this is sufficient as the opcodes are accepted into the next | ||
| release but challenges arise when one or more opcodes are rejected or delayed | ||
| from the release while the opcodes following them are not. In the rejection | ||
| case the opcodes must be burned and in the delayed case the opcodes must be | ||
| manually moved to the next release with special casing code. This proposal | ||
| seaks to implemented a systematic method to handle these issues. |
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.
It has actually been problematic for many releases. Each of these issues has been a PITA for many releases:
- opcodes can't be changed without either a breaking change across in-development driver, compiler, and test scenarios, or burning opcodes, turning them into "reserved".
- The intention is that unused opcodes are removed, and the final opcodes for the next shader model are compacted into the block of final opcodes. This creates a breaking change line again, across compiler version, drivers, and any compiled code.
- Independent feature development requires difficult synchronization since all ops must be serialized into one compact list of enumerated ops.
- There's no way to bridge the transition between preview and final versions.
We never had the opportunity to clean up our ops for SM 6.9 before we found out we couldn't change them. This left multiple ranges of "reserved" DXIL ops behind that are now part of DXIL 1.9, 28 ops in total!
| In most cases this is sufficient as the opcodes are accepted into the next | |
| release but challenges arise when one or more opcodes are rejected or delayed | |
| from the release while the opcodes following them are not. In the rejection | |
| case the opcodes must be burned and in the delayed case the opcodes must be | |
| manually moved to the next release with special casing code. This proposal | |
| seaks to implemented a systematic method to handle these issues. | |
| In some cases this is sufficient, when feature development is unified, opcodes | |
| don't change after being added, and all opcodes in a contiguous block starting | |
| from the prior release are accepted into the next release. | |
| But challenges arise during parallel feature development, from experimental | |
| feature evolution requiring opcode changes, or when a feature and its opcodes | |
| are excluded from the release while the opcodes following them are not. | |
| Excluded opcodes must either be turned into reserved opcodes or a breaking DXIL | |
| change must be synchronized between the compiler, tests, and drivers. | |
| This proposal seeks to implement a systematic method to handle these issues. |
| ## Goals | ||
| This proposal seeks to address the following points: | ||
| * Needless churn when experimental op are delayed or rejected | ||
| * Expermental op boundary point is rigid and moves with every SM update |
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.
| * Expermental op boundary point is rigid and moves with every SM update | |
| * Experimental feature boundaries are rigid and unaffected by SM updates |
| This proposal seeks to address the following points: | ||
| * Needless churn when experimental op are delayed or rejected | ||
| * Expermental op boundary point is rigid and moves with every SM update | ||
| * Long term experiments (and potentially extensions) aren't currently feasible |
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.
| * Long term experiments (and potentially extensions) aren't currently feasible | |
| * Enable long term experiments and potentially extensions |
| * IHV drivers can support both experimental and stable versions of an op simultaneously | ||
| * simplifies migrations |
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.
| * IHV drivers can support both experimental and stable versions of an op simultaneously | |
| * simplifies migrations | |
| * Soft transitions between versions of experimental ops and final ops simplify migrations | |
| * IHV drivers can support multiple experimental versions and the final version of a set of ops in the same driver |
| * Doesn't consume large portions of the current opcode space | ||
| * obvious from reading the DXIL that experimental/extension is being used | ||
| Cons: | ||
| * transistion from experimental to stable isn't just dropping the `x` |
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.
This one actually makes the transition significantly harder than the other options. For the other options, you could use a regex search/replace to update opcodes (with some risk of missing some cases). In theory, you could even add a symbolic opcode replacer to avoid having to ever update the tests.
But with this approach, the instruction stream is changed in a way that can't easily be updated with text search/replace, or maped through a symbolic opcode replacement utility.
| * Unclear how to allocate extension vs experimental ops in the opx space | ||
|
|
||
| ### Extension/Experimental Feature Opcode | ||
| Relaxing the restriction that DXIL opcodes are immediate constants would allow |
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.
I don't know exactly how much we would break with this proposed, but I'm pretty sure it would be a lot. This would be a hard adjustment to make. It complicates DXIL op construction, as you'll need to lookup or create a special op in the entry block just to provide the OpCode.
DXIL op property lookup by OpCode happens a lot for DXIL operations, and this would complicate and increase overhead for that operation.
proposals/xxxx-experimental-dxil.md
Outdated
| * Doesn't consume any of the current opcode space | ||
| * Obvious from reading the DXIL that experimental/extension is being used | ||
| Cons: | ||
| * Transistion from experimental to stable seems quite complicated |
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.
If we were willing to leave the experimental ops in a separate table, we could always do the same with the partitioned approach. Both approaches would leave behind reserved opcode slots for any opcodes deprecated during feature development.
|
|
||
| Intrinsic functions should be handled in a reasonable way. Ideally this means | ||
| that an intrinsic is only available if the experimental/extension op is also | ||
| available. Likely this means updating gen_intrin_main to mark an intrinsic as |
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.
Currently, the way to do this is with a shader model attribute on the intrinsic definition. This could continue to work, but would just require an update to the shader model requirement for experimental feature intrinsics when not being accepted into the next shader model. That's probably not a very big deal to manage actually.
Another approach would be to add a new attribute you can define on the intrinsic, like feature=FeatureName, which would tie the intrinsic to a feature, which could be marked experimental until it ships, at which point it would impact the minimum shader model requirement, just like the shader model attribute.
|
|
||
| ### Single Specific Experimental Opcode with varargs | ||
| A new opcode class `dx.op.extension` is introduced as a core stable opcode in | ||
| which named opcode subsets can be called directly. |
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.
This feels like a non-starter, given the inability to use any of the DXIL op infrastructure for experimental ops, then requiring re-implementation for final ops.
Additionally, we need separate function defs in llvm for different attributes, so we'd at least have to have overload-like permutations keyed off attributes, which the DXIL op system also doesn't do.
Proposal to discuss various options to enable experimental features for DXIL ops and HLSL intrinsics