Skip to content

Commit 86a80e1

Browse files
YuriPlyakhinigcbot
authored andcommitted
Support predicated loads/stores in MemOpt and LdStCombine
This patch adds support for predicated loads and stores in the Memory Optimization (MemOpt) and Load/Store Combination (LdStCombine) passes.
1 parent d6d0b61 commit 86a80e1

33 files changed

+4003
-360
lines changed

IGC/Compiler/CISACodeGen/MemOpt.cpp

Lines changed: 371 additions & 360 deletions
Large diffs are not rendered by default.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; This test is a modification of store_use_vector.ll and it's purpose is to make sure, that debug calls
10+
; are neutral to LdStCombine pass optimizations. They should not be treated as fence-like calls.
11+
;
12+
; REQUIRES: llvm-14-plus, regkeys
13+
;
14+
; RUN: igc_opt --opaque-pointers %s -S -inputocl -igc-ldstcombine -regkey=EnableLdStCombine=1 \
15+
; RUN: -platformbmg \
16+
; RUN: | FileCheck %s
17+
18+
;
19+
; CHECK-LABEL: define spir_kernel void @f0
20+
; CHECK: call void @llvm.genx.GenISA.PredicatedStore.p1.v8i32(ptr addrspace(1) %{{.*}}, <8 x i32> <i32 0, i32 1065353216, i32 1073741824, i32 117835012, i32 8, i32 202050057, i32 269422093, i32 336794129>, i64 32, i1 true)
21+
; CHECK: ret void
22+
23+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-n8:16:32"
24+
target triple = "spir64-unknown-unknown"
25+
26+
%struct.Result = type { [3 x float], [4 x i8], i32, [12 x i8] }
27+
28+
; Function Attrs: convergent nounwind
29+
define spir_kernel void @f0(ptr addrspace(1) %result, <8 x i32> %r0, <8 x i32> %payloadHeader, i16 %localIdX, i16 %localIdY, i16 %localIdZ, ptr %privateBase) {
30+
entry:
31+
%idxprom = zext i16 %localIdX to i64
32+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
33+
%arrayidx1 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 0, i64 0
34+
call void @llvm.genx.GenISA.PredicatedStore.p1.f32(ptr addrspace(1) %arrayidx1, float 0.000000e+00, i64 32, i1 true)
35+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
36+
%arrayidx5 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 0, i64 1
37+
call void @llvm.genx.GenISA.PredicatedStore.p1.f32(ptr addrspace(1) %arrayidx5, float 1.000000e+00, i64 4, i1 true)
38+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
39+
%arrayidx9 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 0, i64 2
40+
call void @llvm.genx.GenISA.PredicatedStore.p1.f32(ptr addrspace(1) %arrayidx9, float 2.000000e+00, i64 8, i1 true)
41+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
42+
%arrayidx12 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 1, i64 0
43+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx12, i8 4, i64 4, i1 true)
44+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
45+
%arrayidx16 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 1, i64 1
46+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx16, i8 5, i64 1, i1 true)
47+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
48+
%arrayidx20 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 1, i64 2
49+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx20, i8 6, i64 2, i1 true)
50+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
51+
%arrayidx24 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 1, i64 3
52+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx24, i8 7, i64 1, i1 true)
53+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
54+
%test0 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 2
55+
call void @llvm.genx.GenISA.PredicatedStore.p1.i32(ptr addrspace(1) %test0, i32 8, i64 16, i1 true)
56+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
57+
%arrayidx32 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 0
58+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32, i8 9, i64 1, i1 true)
59+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
60+
%arrayidx32.1 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 1
61+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.1, i8 10, i64 1, i1 true)
62+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
63+
%arrayidx32.2 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 2
64+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.2, i8 11, i64 1, i1 true)
65+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
66+
%arrayidx32.3 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 3
67+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.3, i8 12, i64 1, i1 true)
68+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
69+
%arrayidx32.4 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 4
70+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.4, i8 13, i64 1, i1 true)
71+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
72+
%arrayidx32.5 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 5
73+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.5, i8 14, i64 1, i1 true)
74+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
75+
%arrayidx32.6 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 6
76+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.6, i8 15, i64 1, i1 true)
77+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
78+
%arrayidx32.7 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 7
79+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.7, i8 16, i64 1, i1 true)
80+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
81+
%arrayidx32.8 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 8
82+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.8, i8 17, i64 1, i1 true)
83+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
84+
%arrayidx32.9 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 9
85+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.9, i8 18, i64 1, i1 true)
86+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
87+
%arrayidx32.10 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 10
88+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.10, i8 19, i64 1, i1 true)
89+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
90+
%arrayidx32.11 = getelementptr inbounds %struct.Result, ptr addrspace(1) %result, i64 %idxprom, i32 3, i64 11
91+
call void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1) %arrayidx32.11, i8 20, i64 1, i1 true)
92+
call void @llvm.dbg.value(metadata i32 0, metadata !9, metadata !DIExpression()), !dbg !11
93+
ret void
94+
}
95+
96+
; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
97+
declare void @llvm.dbg.value(metadata, metadata, metadata) #0
98+
99+
declare void @llvm.genx.GenISA.PredicatedStore.p1.f32(ptr addrspace(1), float, i64, i1)
100+
declare void @llvm.genx.GenISA.PredicatedStore.p1.i8(ptr addrspace(1), i8, i64, i1)
101+
declare void @llvm.genx.GenISA.PredicatedStore.p1.i32(ptr addrspace(1), i32, i64, i1)
102+
103+
!igc.functions = !{!12}
104+
!llvm.dbg.cu = !{!0}
105+
!llvm.debugify = !{!3, !4}
106+
!llvm.module.flags = !{!5}
107+
108+
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
109+
!1 = !DIFile(filename: "DI_call_betwen_stores.ll", directory: "/")
110+
!2 = !{}
111+
!3 = !{i32 13}
112+
!4 = !{i32 11}
113+
!5 = !{i32 2, !"Debug Info Version", i32 3}
114+
!6 = distinct !DISubprogram(name: "test_dbginfo", linkageName: "test_dbginfo", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, unit: !0, retainedNodes: !8)
115+
!7 = !DISubroutineType(types: !2)
116+
!8 = !{!9}
117+
!9 = !DILocalVariable(name: "testvar", scope: !6, file: !1, line: 1, type: !10)
118+
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
119+
!11 = !DILocation(line: 1, column: 1, scope: !6)
120+
!12 = !{ptr @f0, !13}
121+
!13 = !{!14}
122+
!14 = !{!"function_type", i32 0}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
;=========================== begin_copyright_notice ============================
2+
;
3+
; Copyright (C) 2025 Intel Corporation
4+
;
5+
; SPDX-License-Identifier: MIT
6+
;
7+
;============================ end_copyright_notice =============================
8+
9+
; This is to test the optimization. Normally, those tests should use struct as the type for
10+
; loaded value. However, as vector has been extensively optmized. Load combining specially
11+
; generates vector instead of struct for those tests, thus result in less instructions.
12+
13+
; REQUIRES: llvm-14-plus, regkeys
14+
15+
; RUN: igc_opt --opaque-pointers -S -inputocl -igc-ldstcombine -regkey=EnableLdStCombine=5 -platformbmg %s \
16+
; RUN: | FileCheck %s
17+
18+
19+
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-n8:16:32"
20+
target triple = "spir64-unknown-unknown"
21+
22+
23+
; CHECK-LABEL: define spir_kernel void @test_vector_creation
24+
25+
; Function Attrs: convergent nounwind
26+
define spir_kernel void @test_vector_creation(i8 addrspace(1)* %src, <4 x i8> addrspace(1)* %result) #0 {
27+
entry:
28+
29+
; case 0: 4 load i8 --> load i32 --> bitcast <4 x i8> --> store
30+
; handle insertelement
31+
; CHECK-LABEL: c0.base
32+
; CHECK: [[T0_0:%.*]] = call i32 @llvm.genx.GenISA.PredicatedLoad.i32.p1.i32(ptr addrspace(1) %{{.*}}, i32 84148994)
33+
; CHECK: {{.*}} = bitcast i32 [[T0_0]] to <4 x i8>
34+
35+
%c0.base = getelementptr inbounds i8, i8 addrspace(1)* %src, i64 0
36+
%c0.0 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c0.base, i64 1, i1 true, i8 2)
37+
%c0.arrayidx1 = getelementptr inbounds i8, i8 addrspace(1)* %c0.base, i64 1
38+
%c0.1 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c0.arrayidx1, i64 1, i1 true, i8 3)
39+
%c0.arrayidx3 = getelementptr inbounds i8, i8 addrspace(1)* %c0.base, i64 2
40+
%c0.2 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c0.arrayidx3, i64 1, i1 true, i8 4)
41+
%c0.arrayidx5 = getelementptr inbounds i8, i8 addrspace(1)* %c0.base, i64 3
42+
%c0.3 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c0.arrayidx5, i64 1, i1 true, i8 5)
43+
%c0.v.0 = insertelement <4 x i8> undef, i8 %c0.0, i32 0
44+
%c0.v.1 = insertelement <4 x i8> %c0.v.0, i8 %c0.1, i32 1
45+
%c0.v.2 = insertelement <4 x i8> %c0.v.1, i8 %c0.2, i32 2
46+
%c0.v.3 = insertelement <4 x i8> %c0.v.2, i8 %c0.3, i32 3
47+
%c0.dst = getelementptr inbounds <4 x i8>, <4 x i8> addrspace(1)* %result, i64 0
48+
store <4 x i8> %c0.v.3, <4 x i8> addrspace(1)* %c0.dst, align 4
49+
50+
51+
; case 1: [i8, i8, <2 x i8>] --> load i32
52+
; handle insertelement and shufflevector
53+
54+
; CHECK-LABEL: c1.base
55+
; CHECK: [[T1_0:%.*]] = call i32 @llvm.genx.GenISA.PredicatedLoad.i32.p1.i32(ptr addrspace(1) %{{.*}}, i32 84148994)
56+
; CHECK: {{.*}} = bitcast i32 [[T1_0]] to <4 x i8>
57+
58+
%c1.base = getelementptr inbounds i8, i8 addrspace(1)* %src, i64 16
59+
%c1.0 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c1.base, i64 1, i1 true, i8 2)
60+
%c1.arrayidx1 = getelementptr inbounds i8, i8 addrspace(1)* %c1.base, i64 1
61+
%c1.1 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c1.arrayidx1, i64 1, i1 true, i8 3)
62+
%c1.arrayidx3 = getelementptr inbounds i8, i8 addrspace(1)* %c1.base, i64 2
63+
%c1.arrayidx3.0 = bitcast i8 addrspace(1)* %c1.arrayidx3 to <2 x i8> addrspace(1)*
64+
%c1.2 = call <2 x i8> @llvm.genx.GenISA.PredicatedLoad.v2i8.p1v2i8.v2i8(<2 x i8> addrspace(1)* %c1.arrayidx3.0, i64 1, i1 true, <2 x i8> <i8 4, i8 5>)
65+
%c1.2.0 = shufflevector <2 x i8> %c1.2, <2 x i8> undef, <4 x i32> <i32 0, i32 1, i32 undef, i32 undef>
66+
%c1.v.0 = insertelement <4 x i8> undef, i8 %c1.0, i32 0
67+
%c1.v.1 = insertelement <4 x i8> %c1.v.0, i8 %c1.1, i32 1
68+
%c1.v.2 = shufflevector <4 x i8> %c1.v.1, <4 x i8> %c1.2.0, <4 x i32> <i32 0, i32 1, i32 4, i32 5>
69+
%c1.dst = getelementptr inbounds <4 x i8>, <4 x i8> addrspace(1)* %result, i64 2
70+
store <4 x i8> %c1.v.2, <4 x i8> addrspace(1)* %c1.dst, align 4
71+
72+
73+
; case 2: [i8, <2 x i8>, i8] --> load i32
74+
; handle extractelement and insertelement
75+
76+
; CHECK-LABEL: c2.base
77+
; CHECK: [[T2_0:%.*]] = call i32 @llvm.genx.GenISA.PredicatedLoad.i32.p1.i32(ptr addrspace(1) %{{.*}}, i32 84148994)
78+
; CHECK: {{.*}} = bitcast i32 [[T2_0]] to <4 x i8>
79+
80+
%c2.base = getelementptr inbounds i8, i8 addrspace(1)* %src, i64 32
81+
%c2.0 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c2.base, i64 1, i1 true, i8 2)
82+
%c2.arrayidx1 = getelementptr inbounds i8, i8 addrspace(1)* %c2.base, i64 1
83+
%c2.arrayidx1.0 = bitcast i8 addrspace(1)* %c2.arrayidx1 to <2 x i8> addrspace(1)*
84+
%c2.1 = call <2 x i8> @llvm.genx.GenISA.PredicatedLoad.v2i8.p1v2i8.v2i8(<2 x i8> addrspace(1)* %c2.arrayidx1.0, i64 1, i1 true, <2 x i8> <i8 3, i8 4>)
85+
%c2.1.0 = extractelement <2 x i8> %c2.1, i32 0
86+
%c2.1.1 = extractelement <2 x i8> %c2.1, i32 1
87+
%c2.arrayidx3 = getelementptr inbounds i8, i8 addrspace(1)* %c2.base, i64 3
88+
%c2.2 = call i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)* %c2.arrayidx3, i64 1, i1 true, i8 5)
89+
%c2.v.0 = insertelement <4 x i8> undef, i8 %c2.0, i32 0
90+
%c2.v.1 = insertelement <4 x i8> %c2.v.0, i8 %c2.1.0, i32 1
91+
%c2.v.2 = insertelement <4 x i8> %c2.v.1, i8 %c2.1.1, i32 2
92+
%c2.v.3 = insertelement <4 x i8> %c2.v.2, i8 %c2.2, i32 3
93+
%c2.dst = getelementptr inbounds <4 x i8>, <4 x i8> addrspace(1)* %result, i64 4
94+
store <4 x i8> %c2.v.3, <4 x i8> addrspace(1)* %c2.dst, align 4
95+
96+
97+
; case 3 : [ <2 x i8> <2 x i8> ] --> i32
98+
; handle shufflevector
99+
100+
; CHECK-LABEL: c3.base
101+
; CHECK: [[T3_0:%.*]] = call i32 @llvm.genx.GenISA.PredicatedLoad.i32.p1.i32(ptr addrspace(1) %{{.*}}, i32 84148994)
102+
; CHECK: {{.*}} = bitcast i32 [[T3_0]] to <4 x i8>
103+
104+
; CHECK: ret void
105+
106+
%c3.base = getelementptr inbounds i8, i8 addrspace(1)* %src, i64 48
107+
%c3.base.0 = bitcast i8 addrspace(1)* %c3.base to <2 x i8> addrspace(1)*
108+
%c3.arrayidx1 = getelementptr inbounds <2 x i8>, <2 x i8> addrspace(1)* %c3.base.0, i64 0
109+
%c3.0 = call <2 x i8> @llvm.genx.GenISA.PredicatedLoad.v2i8.p1v2i8.v2i8(<2 x i8> addrspace(1)* %c3.arrayidx1, i64 1, i1 true, <2 x i8> <i8 2, i8 3>)
110+
%c3.arrayidx3 = getelementptr inbounds <2 x i8>, <2 x i8> addrspace(1)* %c3.base.0, i64 1
111+
%c3.1 = call <2 x i8> @llvm.genx.GenISA.PredicatedLoad.v2i8.p1v2i8.v2i8(<2 x i8> addrspace(1)* %c3.arrayidx3, i64 1, i1 true, <2 x i8> <i8 4, i8 5>)
112+
%c3.v = shufflevector <2 x i8> %c3.0, <2 x i8> %c3.1, <4 x i32> <i32 0, i32 1, i32 2, i32 3>
113+
%c3.dst = getelementptr inbounds <4 x i8>, <4 x i8> addrspace(1)* %result, i64 10
114+
store <4 x i8> %c3.v, <4 x i8> addrspace(1)* %c3.dst, align 4
115+
116+
ret void
117+
}
118+
119+
; Function Attrs: nounwind readonly
120+
declare i8 @llvm.genx.GenISA.PredicatedLoad.i8.p1i8.i8(i8 addrspace(1)*, i64, i1, i8) #1
121+
; Function Attrs: nounwind readonly
122+
declare <2 x i8> @llvm.genx.GenISA.PredicatedLoad.v2i8.p1v2i8.v2i8(<2 x i8> addrspace(1)*, i64, i1, <2 x i8>) #1
123+
124+
attributes #0 = { convergent nounwind "less-precise-fpmad"="true" "null-pointer-is-valid"="true" }
125+
attributes #1 = { nounwind readonly }

0 commit comments

Comments
 (0)