SPIR-V to DXIL translation generates invalid DXIL in certain cases of input signature
There's a case of valid SPIR-V bytecode that confuses the SPIR-V to DXIL translation code so that it generates invalid DXIL bitcode.
(Tested on latest main
8d3c96a4.)
The following piece of GLSL, once compiled to SPIR-V with glslc -O0 -fshader-stage=vertex --target-env=vulkan1.3 vs.glsl -o vs.spv
(probably the Vulkan version is not relevant) triggers the issue:
#version 450
layout(location = 1) in vec4 vertex_attrib;
void main(){
gl_Position = vec4(vertex_attrib.w, vertex_attrib.z, vertex_attrib.w, float(gl_InstanceIndex));
}
This is the result of running spirv2dxil -s vertex -o vs.dxil vs.spv -v
:
DXIL: Function: main: error: expect Col between 0~1, got 3.
note: at '%2 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 3, i32 undef)' in block '#0' of function 'main'.
Function: main: error: expect Col between 0~1, got 2.
note: at '%1 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 2, i32 undef)' in block '#0' of function 'main'.
Validation failed.
Failed to validate DXIL
Changing location to different values, like 0
or 2
, generates correct DXIL.
DXIL assembly with location=1 (invalid)
;
; Input signature:
;
; Name Index Mask Register SysValue Format Used
; -------------------- ----- ------ -------- -------- ------- ------
; TEXCOORD 1 xyzw 0 NONE float
; SV_InstanceID 0 x 1 INSTID uint
;
;
; Output signature:
;
; Name Index Mask Register SysValue Format Used
; -------------------- ----- ------ -------- -------- ------- ------
; SV_Position 0 xyzw 0 POS float xyzw
;
;
; Pipeline Runtime Information:
;
; Vertex Shader
; OutputPositionPresent=1
;
;
; Input signature:
;
; Name Index InterpMode DynIdx
; -------------------- ----- ---------------------- ------
; TEXCOORD 1
; SV_InstanceID 0
;
; Output signature:
;
; Name Index InterpMode DynIdx
; -------------------- ----- ---------------------- ------
; SV_Position 0 noperspective
;
; Buffer Definitions:
;
;
; Resource Bindings:
;
; Name Type Format Dim ID HLSL Bind Count
; ------------------------------ ---------- ------- ----------- ------- -------------- ------
;
target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-ms-dx"
define void @main() {
%1 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%2 = call float @dx.op.loadInput.f32(i32 4, i32 1, i32 0, i8 3, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%3 = call i32 @dx.op.loadInput.i32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%4 = sitofp i32 %3 to float
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %2) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %1) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %2) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %4) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
ret void
}
; Function Attrs: nounwind readnone
declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0
; Function Attrs: nounwind readnone
declare i32 @dx.op.loadInput.i32(i32, i32, i32, i8, i32) #0
; Function Attrs: nounwind
declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
attributes #0 = { nounwind readnone }
attributes #1 = { nounwind }
!llvm.ident = !{!0}
!dx.version = !{!1}
!dx.valver = !{!2}
!dx.shaderModel = !{!3}
!dx.typeAnnotations = !{!4}
!dx.entryPoints = !{!8}
!0 = !{!"Mesa version 23.0.0-devel (git-4c1131644b)"}
!1 = !{i32 1, i32 2}
!2 = !{i32 1, i32 4}
!3 = !{!"vs", i32 6, i32 2}
!4 = !{i32 1, void ()* @main, !5}
!5 = !{!6}
!6 = !{i32 0, !7, !7}
!7 = !{}
!8 = !{void ()* @main, !"main", !9, null, null}
!9 = !{!10, !15, null}
!10 = !{!11, !13}
!11 = !{i32 0, !"TEXCOORD", i8 9, i8 0, !12, i8 0, i32 1, i8 4, i32 0, i8 0, null}
!12 = !{i32 1}
!13 = !{i32 1, !"SV_InstanceID", i8 5, i8 2, !14, i8 0, i32 1, i8 1, i32 1, i8 0, null}
!14 = !{i32 0}
!15 = !{!16}
!16 = !{i32 0, !"SV_Position", i8 9, i8 3, !14, i8 4, i32 1, i8 4, i32 0, i8 0, null}
DXIL assembly with location=2 (valid)
;
; Input signature:
;
; Name Index Mask Register SysValue Format Used
; -------------------- ----- ------ -------- -------- ------- ------
; TEXCOORD 2 xyzw 0 NONE float
; SV_InstanceID 0 x 1 INSTID uint
;
;
; Output signature:
;
; Name Index Mask Register SysValue Format Used
; -------------------- ----- ------ -------- -------- ------- ------
; SV_Position 0 xyzw 0 POS float xyzw
;
;
; Pipeline Runtime Information:
;
; Vertex Shader
; OutputPositionPresent=1
;
;
; Input signature:
;
; Name Index InterpMode DynIdx
; -------------------- ----- ---------------------- ------
; TEXCOORD 2
; SV_InstanceID 0
;
; Output signature:
;
; Name Index InterpMode DynIdx
; -------------------- ----- ---------------------- ------
; SV_Position 0 noperspective
;
; Buffer Definitions:
;
;
; Resource Bindings:
;
; Name Type Format Dim ID HLSL Bind Count
; ------------------------------ ---------- ------- ----------- ------- -------------- ------
;
target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64"
target triple = "dxil-ms-dx"
define void @main() {
%1 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 2, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%2 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 3, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%3 = call i32 @dx.op.loadInput.i32(i32 4, i32 1, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis)
%4 = sitofp i32 %3 to float
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %2) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 1, float %1) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 2, float %2) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 3, float %4) ; StoreOutput(outputSigId,rowIndex,colIndex,value)
ret void
}
; Function Attrs: nounwind readnone
declare float @dx.op.loadInput.f32(i32, i32, i32, i8, i32) #0
; Function Attrs: nounwind readnone
declare i32 @dx.op.loadInput.i32(i32, i32, i32, i8, i32) #0
; Function Attrs: nounwind
declare void @dx.op.storeOutput.f32(i32, i32, i32, i8, float) #1
attributes #0 = { nounwind readnone }
attributes #1 = { nounwind }
!llvm.ident = !{!0}
!dx.version = !{!1}
!dx.valver = !{!2}
!dx.shaderModel = !{!3}
!dx.typeAnnotations = !{!4}
!dx.entryPoints = !{!8}
!0 = !{!"Mesa version 23.0.0-devel (git-4c1131644b)"}
!1 = !{i32 1, i32 2}
!2 = !{i32 1, i32 4}
!3 = !{!"vs", i32 6, i32 2}
!4 = !{i32 1, void ()* @main, !5}
!5 = !{!6}
!6 = !{i32 0, !7, !7}
!7 = !{}
!8 = !{void ()* @main, !"main", !9, null, null}
!9 = !{!10, !15, null}
!10 = !{!11, !13}
!11 = !{i32 0, !"TEXCOORD", i8 9, i8 0, !12, i8 0, i32 1, i8 4, i32 0, i8 0, null}
!12 = !{i32 2}
!13 = !{i32 1, !"SV_InstanceID", i8 5, i8 2, !14, i8 0, i32 1, i8 1, i32 1, i8 0, null}
!14 = !{i32 0}
!15 = !{!16}
!16 = !{i32 0, !"SV_Position", i8 9, i8 3, !14, i8 4, i32 1, i8 4, i32 0, i8 0, null}
Interestingly enough, if the reference to gl_InstanceIndex
is replaced by a constant in the GLSL code, valid DXIL can still be obtained with location = 1
, like this:
#version 450
layout(location = 1) in vec4 vertex_attrib;
void main(){
gl_Position = vec4(vertex_attrib.w, vertex_attrib.z, vertex_attrib.w, 0.0);
}
Attention: @jenatali