Skip to content

Commit f27e8a5

Browse files
authored
Fix OOB in subscript indexing of col-major matrix in cbuffer (#7866)
A bug in HLOperationLower code that lowers the matrix subscript operation when the matrix is in a cbuffer could cause out-of-bounds alloca indexing. The indexing creates an alloca to store a column-vector loaded from one cbuffer vector. This should have one element per row of the matrix, so it can then index along that dimension using the local array. The bug was using the number of columns when sizing the alloca instead of the number of rows. This caused it to write to out-of-bounds index when the number of rows exceeded the number of columns (like for float3x2). Fixes #7865.
1 parent 98bc4c2 commit f27e8a5

2 files changed

Lines changed: 131 additions & 1 deletion

File tree

lib/HLSL/HLOperationLower.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8405,7 +8405,7 @@ void TranslateCBAddressUserLegacy(Instruction *user, Value *handle,
84058405
// row.z = c[2].[idx]
84068406
// row.w = c[3].[idx]
84078407
Value *Elts[4];
8408-
ArrayType *AT = ArrayType::get(EltTy, MatTy.getNumColumns());
8408+
ArrayType *AT = ArrayType::get(EltTy, MatTy.getNumRows());
84098409

84108410
IRBuilder<> AllocaBuilder(user->getParent()
84118411
->getParent()
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
; RUN: %dxopt %s -hlsl-passes-resume -dxilgen -S | FileCheck %s
2+
3+
; Generated with this, and debug info manually stripped:
4+
; utils/hct/ExtractIRForPassTest.py -p dxilgen -o tools/clang/test/DXC/Passes/DxilGen/cb-col-matrix-subscript-dxilgen.ll <source>.hlsl -- -T vs_6_0
5+
6+
; Source HLSL:
7+
; float3x2 f3x2;
8+
; float main(int row : ROW) : OUT {
9+
; return f3x2[row].y;
10+
; }
11+
12+
; Check cbuffer column-major matrix subscript codegen uses correct alloca size.
13+
14+
; Column-major matrix subscript is lowered in HLOperationLower by:
15+
; Loading one column into an alloca, dynamically indexing that by row,
16+
; then doing the same for the next column.
17+
; Each column is 3 floats for 3 rows. Thus alloca size should be 3 floats.
18+
19+
; Just check the chain for the returned component, skipping the first cbuffer load.
20+
; alloca size should be number of rows (3), not number of columns (2)
21+
; CHECK: %[[alloca:[^ ]+]] = alloca [3 x float]
22+
; Get row index from input:
23+
; CHECK: %[[row:[^ ]+]] = call i32 @dx.op.loadInput.i32(i32 4, i32 0, i32 0, i8 0, i32 undef)
24+
; Load of column 1, skipping column 0:
25+
; CHECK: %[[cbld:[^ ]+]] = call %dx.types.CBufRet.f32 @dx.op.cbufferLoadLegacy.f32(i32 59, %dx.types.Handle %{{[^,]+}}, i32 1)
26+
; Reconstruct vector from original HL op:
27+
; CHECK-NEXT: %[[cbld_x:[^ ]+]] = extractvalue %dx.types.CBufRet.f32 %[[cbld]], 0
28+
; CHECK-NEXT: %[[v3x:[^ ]+]] = insertelement <3 x float> undef, float %[[cbld_x]], i64 0
29+
; CHECK-NEXT: %[[cbld_y:[^ ]+]] = extractvalue %dx.types.CBufRet.f32 %[[cbld]], 1
30+
; CHECK-NEXT: %[[v3xy:[^ ]+]] = insertelement <3 x float> %[[v3x]], float %[[cbld_y]], i64 1
31+
; CHECK-NEXT: %[[cbld_z:[^ ]+]] = extractvalue %dx.types.CBufRet.f32 %[[cbld]], 2
32+
; CHECK-NEXT: %[[v3xyz:[^ ]+]] = insertelement <3 x float> %[[v3xy]], float %[[cbld_z]], i64 2
33+
; Store y column to alloca:
34+
; CHECK-NEXT: %[[ee:[^ ]+]] = extractelement <3 x float> %[[v3xyz]], i32 0
35+
; CHECK-NEXT: %[[gep_alloca_0:[^ ]+]] = getelementptr inbounds [3 x float], [3 x float]* %[[alloca]], i32 0, i32 0
36+
; CHECK-NEXT: store float %[[ee]], float* %[[gep_alloca_0]]
37+
; CHECK-NEXT: %[[ee:[^ ]+]] = extractelement <3 x float> %[[v3xyz]], i32 1
38+
; CHECK-NEXT: %[[gep_alloca_1:[^ ]+]] = getelementptr inbounds [3 x float], [3 x float]* %[[alloca]], i32 0, i32 1
39+
; CHECK-NEXT: store float %[[ee]], float* %[[gep_alloca_1]]
40+
; CHECK-NEXT: %[[ee:[^ ]+]] = extractelement <3 x float> %[[v3xyz]], i32 2
41+
; CHECK-NEXT: %[[gep_alloca_2:[^ ]+]] = getelementptr inbounds [3 x float], [3 x float]* %[[alloca]], i32 0, i32 2
42+
; CHECK-NEXT: store float %[[ee]], float* %[[gep_alloca_2]]
43+
; Load [row].y from alloca:
44+
; CHECK-NEXT: %[[gep_alloca_row:[^ ]+]] = getelementptr inbounds [3 x float], [3 x float]* %[[alloca]], i32 0, i32 %[[row]]
45+
; CHECK-NEXT: %[[load_row:[^ ]+]] = load float, float* %[[gep_alloca_row]]
46+
; Insert [row].x into vec2 (unused)
47+
; CHECK-NEXT: %[[v2x:[^ ]+]] = insertelement <2 x float> undef, float %{{[^,]+}}, i64 0
48+
; Insert [row].y into vec2
49+
; CHECK-NEXT: %[[v2xy:[^ ]+]] = insertelement <2 x float> %[[v2x]], float %[[load_row]], i64 1
50+
; Extract component for .y output:
51+
; CHECK-NEXT: %[[ee:[^ ]+]] = extractelement <2 x float> %[[v2xy]], i32 1
52+
; CHECK-NEXT: call void @dx.op.storeOutput.f32(i32 5, i32 0, i32 0, i8 0, float %[[ee]])
53+
54+
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"
55+
target triple = "dxil-ms-dx"
56+
57+
%"$Globals" = type { %class.matrix.float.3.2 }
58+
%class.matrix.float.3.2 = type { [3 x <2 x float>] }
59+
%dx.types.Handle = type { i8* }
60+
%dx.types.ResourceProperties = type { i32, i32 }
61+
62+
@"$Globals" = external constant %"$Globals"
63+
64+
; Function Attrs: nounwind readnone
65+
declare <2 x float>* @"dx.hl.subscript.colMajor[].rn.<2 x float>* (i32, %class.matrix.float.3.2*, i32, i32)"(i32, %class.matrix.float.3.2*, i32, i32) #0
66+
67+
; Function Attrs: nounwind readnone
68+
declare %"$Globals"* @"dx.hl.subscript.cb.rn.%\22$Globals\22* (i32, %dx.types.Handle, i32)"(i32, %dx.types.Handle, i32) #0
69+
70+
; Function Attrs: nounwind readnone
71+
declare %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22$Globals\22*, i32)"(i32, %"$Globals"*, i32) #0
72+
73+
; Function Attrs: nounwind readnone
74+
declare %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %\22$Globals\22)"(i32, %dx.types.Handle, %dx.types.ResourceProperties, %"$Globals") #0
75+
76+
; Function Attrs: nounwind
77+
define void @main(float* noalias, i32) #1 {
78+
entry:
79+
%2 = call %dx.types.Handle @"dx.hl.createhandle..%dx.types.Handle (i32, %\22$Globals\22*, i32)"(i32 0, %"$Globals"* @"$Globals", i32 0)
80+
%3 = call %dx.types.Handle @"dx.hl.annotatehandle..%dx.types.Handle (i32, %dx.types.Handle, %dx.types.ResourceProperties, %\22$Globals\22)"(i32 14, %dx.types.Handle %2, %dx.types.ResourceProperties { i32 13, i32 28 }, %"$Globals" undef)
81+
%4 = call %"$Globals"* @"dx.hl.subscript.cb.rn.%\22$Globals\22* (i32, %dx.types.Handle, i32)"(i32 6, %dx.types.Handle %3, i32 0)
82+
%5 = getelementptr inbounds %"$Globals", %"$Globals"* %4, i32 0, i32 0
83+
%6 = add i32 3, %1
84+
%7 = call <2 x float>* @"dx.hl.subscript.colMajor[].rn.<2 x float>* (i32, %class.matrix.float.3.2*, i32, i32)"(i32 1, %class.matrix.float.3.2* %5, i32 %1, i32 %6)
85+
%8 = load <2 x float>, <2 x float>* %7
86+
%9 = extractelement <2 x float> %8, i32 1
87+
store float %9, float* %0
88+
ret void
89+
}
90+
91+
attributes #0 = { nounwind readnone }
92+
attributes #1 = { nounwind }
93+
94+
!llvm.module.flags = !{!0}
95+
!pauseresume = !{!1}
96+
!llvm.ident = !{!2}
97+
!dx.version = !{!3}
98+
!dx.valver = !{!4}
99+
!dx.shaderModel = !{!5}
100+
!dx.typeAnnotations = !{!6, !10}
101+
!dx.entryPoints = !{!19}
102+
!dx.fnprops = !{!23}
103+
!dx.options = !{!24, !25}
104+
105+
!0 = !{i32 2, !"Debug Info Version", i32 3}
106+
!1 = !{!"hlsl-hlemit", !"hlsl-hlensure"}
107+
!2 = !{!"dxc(private) 1.9.0.5175 (dxc-version-print, 93ba0122d-dirty)"}
108+
!3 = !{i32 1, i32 0}
109+
!4 = !{i32 1, i32 10}
110+
!5 = !{!"vs", i32 6, i32 0}
111+
!6 = !{i32 0, %"$Globals" undef, !7}
112+
!7 = !{i32 28, !8}
113+
!8 = !{i32 6, !"f3x2", i32 2, !9, i32 3, i32 0, i32 7, i32 9}
114+
!9 = !{i32 3, i32 2, i32 2}
115+
!10 = !{i32 1, void (float*, i32)* @main, !11}
116+
!11 = !{!12, !14, !17}
117+
!12 = !{i32 0, !13, !13}
118+
!13 = !{}
119+
!14 = !{i32 1, !15, !16}
120+
!15 = !{i32 4, !"OUT", i32 7, i32 9}
121+
!16 = !{i32 0}
122+
!17 = !{i32 0, !18, !16}
123+
!18 = !{i32 4, !"ROW", i32 7, i32 4}
124+
!19 = !{void (float*, i32)* @main, !"main", null, !20, null}
125+
!20 = !{null, null, !21, null}
126+
!21 = !{!22}
127+
!22 = !{i32 0, %"$Globals"* @"$Globals", !"$Globals", i32 0, i32 -1, i32 1, i32 28, null}
128+
!23 = !{void (float*, i32)* @main, i32 1}
129+
!24 = !{i32 64}
130+
!25 = !{i32 -1}

0 commit comments

Comments
 (0)