DXIL之类型体系
DXIL之类型体系
DXIL 中大部分 LLVM 类型系统的构造都是合法的。基本类型
支持以下基本类型:
- void
- metadata
- i1, i8, i16, i32, i64
- half, float, double
SM6.0 假设原生硬件支持 i32 和 float 类型。
i8 仅在一些内置函数中用于表示掩码、枚举常量值或元数据,它不支持在着色器中进行内存访问或计算。
HLSL 中的 min12int、min16int 和 min16uint 数据类型被映射为 i16。
在 SM6.0 中,half 和 i16 被视为对应的 DXBC min-precision 类型(min16float、min16int/min16uint)。
HLSL 编译器优化器将 half、i16 和 i8 数据视为硬件原生支持的数据类型;也就是说,饱和度、范围裁剪以及 INF/NaN 处理都按照 IEEE 标准进行。这样的语义允许优化器重用 LLVM 优化 passes。
硬件对于双精度(double)的支持是可选的,并且由 RequiresHardwareDouble CAP 位进行保护。
硬件对于 i64 的支持是可选的,并且由 CAP 位进行保护。
向量 Vectors
HLSL 向量会被标量化。它们不参与计算,但可以在声明中存在,以将原始变量布局传达给工具、调试器和反射机制。 未来的 DXIL 可能会增加对于 <2 x half> 和 <2 x i16> 向量的支持,或是提供关于打包相关 half 和 i16 数量的提示。
矩阵 Matrics
矩阵会被降低为向量,并且不会被指令引用。它们可以在声明中存在,以将原始变量布局传达给工具、调试器和反射机制。
数组 Arrays
指令只能引用一维基本类型数组。然而,复杂的数组,例如多维数组或用户定义类型,可以存在以将基本变量布局传达给工具、调试器和反射机制。用户定义的类型
原始的 HLSL 用户自定义类型(UDT)会被降级,不会被指令引用。然而,它们可以在声明中存在,以将原始变量布局传达给工具、调试器和反射机制。某些资源操作会返回“分组”UDT,用于将多个返回值组合在一起;这样的UDT会立即被“解构”,转换为组件,然后被其他指令使用。类型转换
LLVM指令支持类型之间的显式转换。精度限定符
默认情况下,所有的浮点数 HLSL 操作被视为“快速”或非精确的操作。HLSL 和驱动程序编译器可以对这些操作进行重构。非精确的 LLVM 指令包括:fadd、fsub、fmul、fdiv、frem、fcmp,它们都标有“快速”数学标志。HLSL 中的 precise 类型限定符要求所有对值有贡献的操作在进行优化时都需要遵守 IEEE 标准。编译器开关 /Gis 隐式地将所有变量和值声明为 precise 类型。
精确行为在 LLVM 指令中以不设置“快速”数学标志的方式表示:fadd、fsub、fmul、fdiv、frem、fcmp。每个与计算精确值相关的调用指令都用 dx.precise 元数据进行注释,指示驱动程序编译器不得执行不符合 IEEE 标准的优化操作。
类型注释
在DXIL中,用户自定义类型可以用于为结构字段“附加”其他属性。例如,DXIL可以包含用于反射目的的结构和函数的类型注释。
namespace MyNameSpace {
struct MyType {
float field1;
int2 field2;
};
}
float main(float col : COLOR) : SV_Target {
.....
}
!dx.typeAnnotations = !{!3, !7}
!3 = !{i32 0, %"struct.MyNameSpace::MyType" undef, !4}
!4 = !{i32 12, !5, !6}
!5 = !{i32 6, !"field1", i32 3, i32 0, i32 7, i32 9}
!6 = !{i32 6, !"field2", i32 3, i32 4, i32 7, i32 4}
!7 = !{i32 1, void (float, float*)* @"main", !8}
!8 = !{!9, !11, !14}
!9 = !{i32 0, !10, !10}
!10 = !{}
!11 = !{i32 0, !12, !13}
!12 = !{i32 4, !"COLOR", i32 7, i32 9}
!13 = !{i32 0}
!14 = !{i32 1, !15, !13}
!15 = !{i32 4, !"SV_Target", i32 7, i32 9}
!16 = !{null, !"lib.no::entry", null, null, null}
类型/字段注释元数据层次结构在DXIL中递归地模仿了LLVM类型层次结构。dx.typeAnnotations是一种类型注释节点的元数据,其中每个节点代表特定类型的类型注释。
对于每个类型注释节点,第一个值表示注释的类型:
!3 = !{i32 0, %"struct.MyNameSpace::MyType" undef, !4}
!7 = !{i32 1, void (float, float*)* @"main", !8}
!3是一个节点表示一种类型, !7是一种节点表示一种类型。
!dx.typeAnnotations = !{!3, !7}
| Idx | type |
|---|---|
| 0 | 结构体注释 |
| 1 | 函数注释 |
第二个值表示名称,第三个值是相应的类型元数据节点。
结构体注解从结构体大小(以字节为单位)开始,然后是字段注解列表:
!4 = !{i32 12, !5, !6}
!5 = !{i32 6, !"field1", i32 3, i32 0, i32 7, i32 9}
!6 = !{i32 6, !"field2", i32 3, i32 4, i32 7, i32 4}
!4中描述了结构体总大小是12字节,第一个字段放在!5中,第2个字段放在!6中。
字段注释是一系列由标签号和其值组成的对。字段注释对的定义如下:
| Idx | Type |
|---|---|
| 0 | SNorm |
| 1 | UNorm |
| 2 | Matrix |
| 3 | Buffer Offset |
| 4 | Semantic String |
| 5 | Interpolation Mode |
| 6 | Field Name |
| 7 | Component Type |
| 8 | Precise |
函数注解是一系列的参数注解:
!7 = !{i32 1, void (float, float*)* @"main", !8}
!8 = !{!9, !11, !14}
每个参数注解包含输入/输出类型,字段注释和语义索引:
!9 = !{i32 0, !10, !10}
!10 = !{}
!11 = !{i32 0, !12, !13}
!12 = !{i32 4, !"COLOR", i32 7, i32 9}
!13 = !{i32 0}
!14 = !{i32 1, !15, !13}
!15 = !{i32 4, !"SV_Target", i32 7, i32 9}
浙公网安备 33010602011771号