| title | params | |||||||
|---|---|---|---|---|---|---|---|---|
[0039] - Element-aligned vectors |
|
- Issues:
- PRs:
Vectors in DirectX and SPIR-V are generally element-aligned, but this isn't representable in LLVM's datalayout, and even if it were Clang makes assumptions that vectors are aligned to the vector size or the next power of two without consulting the target at all.
The alignment of vectors affects how structs and arrays containing these types are laid out in memory. These layouts need to be compatible with how DirectX and Vulkan specify such objects are laid out, otherwise data placed in buffers, textures, and cbuffers will be in the wrong place and shader programs won't function correctly.
The issues around these types tend to mostly come up with 2- and 3-element vectors, as 4-element vectors usually line up with 16-byte boundary related language rules, so the fact that we treat them as overaligned isn't observable.
We propose a specification to LLVM's DataLayout string to say that vectors are element-aligned by default, and a bit to Clang's TargetInfo to say that vectors are element-aligned for a target. These will need to be kept in sync for a given target, but this is already true for most of the values in Clang's TargetInfo.
We can then update the DirectX and SPIR-V targets to use this specifier.
For DirectX, vector and matrix types are aligned by their component type's alignment. Using an element-aligned default for vectors matches the DXC behaviour and driver expectations.
For SPIR-V, element-alignment is specified in Vulkan for both "Standard Uniform Buffer Layout" and "Standard Storage Buffer Layout". Additionally, element-alignment matches all four of DXC's options for memory layout rules when emitting SPIR-V.
- Add and document a "ve" specifier to the Data Layout string, which specifies that vectors are element-aligned unless they have a more specific rule.
- Add a boolean value to
clang::TransferrableTargetInfosaying thatVectorsAreElementAligned. - Update the DirectX and SPIR-V targets to specify both of these.
For DirectX, the new Data Layout would be as follows:
e-m:e-ve-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-f64:64-n8:16:32:64"
For SPIR-V, we should be able to simplify the existing Data Layout strings so that the logical SPIR-V triple (for example), is just:
e-ve-i64:64-n8:16:32:64-G10
There are a details about how we could specify element-alignment in the Data Layout that we do not intend to pursue at this time:
- Alternative spellings to "ve"
- Also including an explicit "vectors are not element-aligned" specifier, such as "vE".
- Enhance the
v<size>:<abi>[:<pref>]syntax to allow an 'e' for element in the<abi>and<pref>sections. This has two disadvantages:- The logic for parsing vectors and scalars is shared, so we'd need to explicitly reject 'e' for scalars.
- We would need to specify this for every size of vector
- Allow
<size>to be omitted inv<size>:<abi>[:<pref>]. In combination with the previous option, this could do what we need. The problem is that this doesn't really make sense otherwise, as setting all vectors to a fixed alignment isn't likely to be useful.
We could potentially avoid touching the Data Layout at all if we were to modify the HLSL frontend to explicitly put an alignment on all vector types. This nearly works but has a couple of problems:
- Vectors can be created by compiler transformations, and these are outside of the scope of where the frontend could insert explicit alignment.
- This ties the alignment to the frontend rather than the backends, forcing all targets of HLSL to use this alignment. This wouldn't necessarily make sense if we were targetting something other than DirectX or SPIR-V.