@@ -448,26 +448,25 @@ particular entry point is linked to a final shader.
448
448
449
449
### Clang Frontend
450
450
451
- Unbound resources will be initialized by a resource class constructor that takes
452
- 3 arguments - the `space`, `range` and `index`. This constructor will be
453
- declared in `HLSLExternalSemaSource` as part of resource class setup.
451
+ Unbound resources will be initialized by a resource class constructor for
452
+ implicit binding which is described [here](0025-resource-constructors.md#constructor-for-resources-with-implicit-binding).
454
453
455
- The arguments specify the virtual register space (defaulting to 0),
456
- required descriptor range and an index of the resource in the range.
454
+ The `order_id` number will be generated by in `SemaHLSL` class and it will
455
+ be used to uniquely identify the unbound resource, and it will also reflect the
456
+ order in which the resource has been declared. Implicit binding assignments
457
+ depend on the order the resources were declared, so this will help the compiler
458
+ to preserve the order. Additionally, it will also help the compiler distinquish
459
+ between individual resources with the same type and binding range.
457
460
458
461
The constructor will call Clang builtin function
459
- `__builtin_hlsl_create_handle_from_implicit_binding` and will pass along the
460
- `space`, `range` and `index` values, and it will also include the uninitialized
461
- resource handle. The type of the handle argument will be used to infer the
462
- specific resource handle type returned by the buildin function. This will happen
463
- in `SemaHLSL::CheckBuiltinFunctionCall` the same way we infer return types for
464
- HLSL intrinsic builtins based on the builtin arguments.
462
+ `__builtin_hlsl_create_handle_from_implicit_binding` and will pass along all the
463
+ arguments provided to the constructor plus the resource handle.
465
464
466
465
```c++
467
466
template <typename T> class RWBuffer<T> {
468
- RWBuffer(unsigned space , int range, unsigned index) {
469
- __handle = __builtin_hlsl_create_handle_from_implicit_binding (__handle, space , range, index);
470
- }
467
+ RWBuffer(unsigned spaceNo , int range, unsigned index, unsigned orderId, const char *name ) {
468
+ __handle = __builtin_hlsl_resource_createhandlefromimplicitbinding (__handle, spaceNo , range, index, orderId, name );
469
+ }
471
470
}
472
471
```
473
472
@@ -485,36 +484,72 @@ The signature of the `@llvm.dx.resource.handlefromimplicitbinding` intrinsic wil
485
484
| %space | i32 | Virtual register space |
486
485
| %range | i32 | Range size of the binding |
487
486
| %index | i32 | Index from the beginning of the binding |
487
+ | %name | ptr | Pointer to a global constant string that is the name of the resource |
488
488
489
489
_ Note: We might need to add a uniformity bit here, unless we can derive it from uniformity analysis._
490
490
491
- The ` order_id ` number will be generated by Clang Codegen in ` GCHLSLRuntime ` . It
492
- will be used to uniquely identify the unbound resource, and it will also reflect
493
- the order in which the resource has been declared. Implicit binding assignments
494
- depend on the order the resources were declared, so this will help the compiler
495
- to preserve the order. Additionally, it will also help the compiler distinquish
496
- between individual resources with the same type and binding range.
497
-
498
491
### LLVM Binding Assignment Pass
499
492
500
- The implicit binding assignment for DirectX will happen in an LLVM pass
501
- ` DXILResourceImplicitBindings ` . The pass will scan the module for all instances of
502
- ` @llvm.dx.resource.handlefrombinding ` and create a map of available register
503
- slots. Then it will gather all instances of
504
- ` @llvm.dx.resource.handlefromimplicitbinding ` calls and sort them by
505
- ` %order_id ` . Then for each group of calls operating on the same unique resource
506
- it will:
493
+ The implicit binding assignment will happen in two phases - ` DXILResourceBindingAnalysis ` and ` DXILResourceImplicitBindings ` .
494
+
495
+ #### 1. Analysis of available register spaces
496
+
497
+ A new ` DXILResourceBindingAnalysis ` will scan the module for all instances of
498
+ ` @llvm.dx.resource.handlefrombinding ` calls and create a map of available
499
+ register slots and spaces. The results of the analysis will be stored in
500
+ ` DXILResourceBindingInfo ` .
501
+
502
+ While the map is being created the analysis can easily detect whether any of the
503
+ register bindings overlap, which is something the compiler needs to diagnose.
504
+ However, in order to issue a useful error message for this, the analysis would
505
+ have to track which register ranges are occupied by which resource. That is
506
+ beyond the need of the common case scenario where all bindings are correct and
507
+ the analysis just need to figure out the available register slot ranges.
508
+
509
+ For this reason if the analysis finds that some register bindings overlap, it
510
+ will prioritize performance for the common case and just set the
511
+ ` hasOverlappingBinding ` flag on ` DXILResourceBindingInfo ` to true. The detailed
512
+ error message calculation for the uncommon failure code path will happen later
513
+ in ` DXILPostOptimizationValidation ` pass which can analyze the resource bindings
514
+ in more detail and report exactly which resources are overlapping and where.
515
+
516
+ This is the same principle that we use when detecting invalid counter usage for
517
+ structured buffers as described
518
+ [ here] ( 0022-resource-instance-analysis.md ) .
519
+
520
+ While scanning for the ` @llvm.dx.resource.handlefrombinding ` calls the analysis
521
+ can also take note on whether there are any
522
+ ` @llvm.dx.resource.handlefromimplicitbinding ` calls in the module. If there are,
523
+ it will set the ` hasImplicitBinding ` flag on ` DXILResourceBindingInfo ` to true.
524
+ This will enable the follow-up ` DXILResourceImplicitBindings ` pass to exit early
525
+ if there are no implicit bindings in the module.
526
+
527
+ _ Note: In general diagnostics should not be raised in LLVM analyses or
528
+ passes. Analyses may be invalidated and re-ran several times, increasing
529
+ performance impact and raising repeated diagnostics. Diagnostics raised after
530
+ transformations passes also lose source context resulting in less useful error
531
+ messages. However the shader compiler requires certain validations to be done
532
+ after code optimizations which requires the diagnostic to be raised from a pass.
533
+ Impact is minimized by raising the diagnostic only from a limited set of passes
534
+ and minimizing computation in the common case._
535
+
536
+ #### 2. Assign bindings to implictily bound resource
537
+
538
+ The implicit binding assignment will happen in an LLVM pass
539
+ ` DXILResourceImplicitBindings ` . The pass will use the map of available register
540
+ spaces ` DXILResourceBindingInfo ` created by ` DXILResourceBindingAnalysis ` . It
541
+ will scan the module for all instances of
542
+ ` @llvm.dx.resource.handlefromimplicitbinding ` calls, sort them by ` order_id ` ,
543
+ and then for each group of calls operating on the same unique resource it will:
507
544
- find an available space to bind the resource based on the resource class,
508
- required range and space
545
+ required range and space
509
546
- replace the ` @llvm.dx.resource.handlefromimplicitbinding ` calls and all of their
510
- uses with ` @llvm.dx.resource.handlefrombinding ` using the new binding
547
+ uses with ` @llvm.dx.resource.handlefrombinding ` with the assigned binding
511
548
512
549
The ` DXILResourceImplicitBindings ` pass needs to run after all IR optimizations
513
- passes but before any pass or analysis that relies on
514
- ` @llvm.dx.resource.handlefrombinding ` calls to exist for all non-dynamically
515
- bound resources used by the shader. For example, it needs to run before any pass
516
- that requires ` DXILResourceAnalysis ` . The pass invalidate any existing
517
- ` DXILResourceAnalysis ` if it assigns any new bindings.
550
+ passes but before any pass that depends on ` DXILResourceAnalysis ` which relies
551
+ on ` @llvm.dx.resource.handlefrombinding ` calls to exist for all non-dynamically
552
+ bound resources used by the shader.
518
553
519
554
## Alternatives considered (Optional)
520
555
0 commit comments