Skip to content

Commit fc73b6b

Browse files
MrSidimsvladimirlaz
authored andcommitted
Fix LoopControl parameters order
3.23 Loop Control: If there are multiple following operands indicated, they are ordered: Those indicated by smaller-numbered bits appear first. This rule was violated in previous implementation. Signed-off-by: Dmitry Sidorov <[email protected]>
1 parent 9e1c7d7 commit fc73b6b

File tree

3 files changed

+169
-11
lines changed

3 files changed

+169
-11
lines changed

llvm-spirv/lib/SPIRV/SPIRVReader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ void SPIRVToLLVM::setLLVMLoopMetadata(const LoopInstType *LM,
864864
Parameters.push_back(SafelenMDOp);
865865
Metadata.push_back(llvm::MDNode::get(*Context, Parameters));
866866
}
867+
++NumParam;
867868
}
868869
if (LC & LoopControlPipelineEnableINTELMask) {
869870
Metadata.push_back(llvm::MDNode::get(

llvm-spirv/lib/SPIRV/SPIRVWriter.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
964964
return spv::LoopControlMaskNone;
965965

966966
size_t LoopControl = spv::LoopControlMaskNone;
967+
std::vector<std::pair<SPIRVWord, SPIRVWord>> ParametersToSort;
967968

968969
// Unlike with most of the cases, some loop metadata specifications
969970
// can occur multiple times - for these, all correspondent tokens
@@ -988,13 +989,13 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
988989
else if (S == "llvm.loop.unroll.count" &&
989990
!(LoopControl & LoopControlDontUnrollMask)) {
990991
size_t I = getMDOperandAsInt(Node, 1);
991-
Parameters.push_back(I);
992+
ParametersToSort.emplace_back(spv::LoopControlPartialCountMask, I);
992993
LoopControl |= spv::LoopControlPartialCountMask;
993994
} else if (S == "llvm.loop.ivdep.enable")
994995
LoopControl |= spv::LoopControlDependencyInfiniteMask;
995996
else if (S == "llvm.loop.ivdep.safelen") {
996997
size_t I = getMDOperandAsInt(Node, 1);
997-
Parameters.push_back(I);
998+
ParametersToSort.emplace_back(spv::LoopControlDependencyLengthMask, I);
998999
LoopControl |= spv::LoopControlDependencyLengthMask;
9991000
} else if (BM->isAllowedToUseExtension(
10001001
ExtensionID::SPV_INTEL_fpga_loop_controls)) {
@@ -1003,13 +1004,15 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
10031004
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10041005
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10051006
size_t I = getMDOperandAsInt(Node, 1);
1006-
Parameters.push_back(I);
1007+
ParametersToSort.emplace_back(
1008+
spv::LoopControlInitiationIntervalINTELMask, I);
10071009
LoopControl |= spv::LoopControlInitiationIntervalINTELMask;
10081010
} else if (S == "llvm.loop.max_concurrency.count") {
10091011
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10101012
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10111013
size_t I = getMDOperandAsInt(Node, 1);
1012-
Parameters.push_back(I);
1014+
ParametersToSort.emplace_back(spv::LoopControlMaxConcurrencyINTELMask,
1015+
I);
10131016
LoopControl |= spv::LoopControlMaxConcurrencyINTELMask;
10141017
} else if (S == "llvm.loop.parallel_access_indices") {
10151018
// Intel FPGA IVDep loop attribute
@@ -1027,7 +1030,8 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
10271030
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10281031
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10291032
size_t I = getMDOperandAsInt(Node, 1);
1030-
Parameters.push_back(I);
1033+
ParametersToSort.emplace_back(spv::LoopControlPipelineEnableINTELMask,
1034+
I);
10311035
LoopControl |= spv::LoopControlPipelineEnableINTELMask;
10321036
} else if (S == "llvm.loop.coalesce.enable") {
10331037
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
@@ -1037,19 +1041,22 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
10371041
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10381042
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10391043
size_t I = getMDOperandAsInt(Node, 1);
1040-
Parameters.push_back(I);
1044+
ParametersToSort.emplace_back(spv::LoopControlLoopCoalesceINTELMask,
1045+
I);
10411046
LoopControl |= spv::LoopControlLoopCoalesceINTELMask;
10421047
} else if (S == "llvm.loop.max_interleaving.count") {
10431048
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10441049
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10451050
size_t I = getMDOperandAsInt(Node, 1);
1046-
Parameters.push_back(I);
1051+
ParametersToSort.emplace_back(
1052+
spv::LoopControlMaxInterleavingINTELMask, I);
10471053
LoopControl |= spv::LoopControlMaxInterleavingINTELMask;
10481054
} else if (S == "llvm.loop.intel.speculated.iterations.count") {
10491055
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10501056
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10511057
size_t I = getMDOperandAsInt(Node, 1);
1052-
Parameters.push_back(I);
1058+
ParametersToSort.emplace_back(
1059+
spv::LoopControlSpeculatedIterationsINTELMask, I);
10531060
LoopControl |= spv::LoopControlSpeculatedIterationsINTELMask;
10541061
}
10551062
}
@@ -1061,16 +1068,27 @@ LLVMToSPIRV::getLoopControl(const BranchInst *Branch,
10611068
if (!DependencyArrayParameters.empty()) {
10621069
// The first parameter states the number of <array, safelen> pairs to be
10631070
// listed
1064-
Parameters.push_back(DependencyArrayParameters.size());
1071+
ParametersToSort.emplace_back(spv::LoopControlDependencyArrayINTELMask,
1072+
DependencyArrayParameters.size());
10651073
for (auto &ArraySflnPair : DependencyArrayParameters) {
1066-
Parameters.push_back(ArraySflnPair.first);
1067-
Parameters.push_back(ArraySflnPair.second);
1074+
ParametersToSort.emplace_back(spv::LoopControlDependencyArrayINTELMask,
1075+
ArraySflnPair.first);
1076+
ParametersToSort.emplace_back(spv::LoopControlDependencyArrayINTELMask,
1077+
ArraySflnPair.second);
10681078
}
10691079
BM->addExtension(ExtensionID::SPV_INTEL_fpga_loop_controls);
10701080
BM->addCapability(CapabilityFPGALoopControlsINTEL);
10711081
LoopControl |= spv::LoopControlDependencyArrayINTELMask;
10721082
}
10731083

1084+
std::sort(ParametersToSort.begin(), ParametersToSort.end(),
1085+
[](const std::pair<SPIRVWord, SPIRVWord> &CompareLeft,
1086+
const std::pair<SPIRVWord, SPIRVWord> &CompareRight) {
1087+
return CompareLeft.first < CompareRight.first;
1088+
});
1089+
for (auto Param : ParametersToSort)
1090+
Parameters.push_back(Param.second);
1091+
10741092
return static_cast<spv::LoopControlMask>(LoopControl);
10751093
}
10761094

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
; RUN: llvm-as < %s > %t.bc
2+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_loop_controls -o - -spirv-text | FileCheck %s --check-prefix=CHECK-SPIRV
3+
4+
; RUN: llvm-spirv %t.bc --spirv-ext=+SPV_INTEL_fpga_loop_controls -o %t.spv
5+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
6+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM
7+
8+
; RUN: llvm-spirv %t.bc -o - -spirv-text | FileCheck %s --check-prefix=CHECK-SPIRV-NEGATIVE
9+
10+
; RUN: llvm-spirv %t.bc -o %t.spv
11+
; RUN: llvm-spirv -r %t.spv -o %t.rev.bc
12+
; RUN: llvm-dis < %t.rev.bc | FileCheck %s --check-prefix=CHECK-LLVM-NEGATIVE
13+
14+
; CHECK-SPIRV: Capability FPGALoopControlsINTEL
15+
; CHECK-SPIRV: Extension "SPV_INTEL_fpga_loop_controls"
16+
; CHECK-SPIRV-NEGATIVE-NOT: Capability FPGALoopControlsINTEL
17+
; CHECK-SPIRV-NEGATIVE-NOT: Extension "SPV_INTEL_fpga_loop_controls"
18+
; CHECK-SPIRV: 4522248 3 2 1 1 16 3 0
19+
; CHECK-SPIRV-NEGATIVE: LoopMerge {{[0-9]+}} {{[0-9]+}} 264 3 2
20+
21+
; CHECK-LLVM: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD:[0-9]+]]
22+
; CHECK-LLVM: ![[MD]] = distinct !{![[MD]], ![[MD_ivdep:[0-9]+]], ![[MD_unroll:[0-9]+]], ![[MD_ii:[0-9]+]], ![[MD_access:[0-9]+]], ![[MD_si:[0-9]+]]}
23+
; CHECK-LLVM: ![[MD_ivdep]] = !{!"llvm.loop.ivdep.safelen", i32 3}
24+
; CHECK-LLVM: ![[MD_unroll]] = !{!"llvm.loop.unroll.count", i32 2}
25+
; CHECK-LLVM: ![[MD_ii]] = !{!"llvm.loop.ii.count", i32 1}
26+
; CHECK-LLVM: ![[MD_access]] = !{!"llvm.loop.parallel_access_indices", !{{[0-9]+}}, i32 3}
27+
; CHECK-LLVM: ![[MD_si]] = !{!"llvm.loop.intel.speculated.iterations.count", i32 0}
28+
29+
; CHECK-LLVM-NEGATIVE: br label %for.cond{{[0-9]*}}, !llvm.loop ![[MD:[0-9]+]]
30+
; CHECK-LLVM-NEGATIVE: ![[MD]] = distinct !{![[MD]], ![[MD_ivdep:[0-9]+]], ![[MD_unroll:[0-9]+]]}
31+
; CHECK-LLVM-NEGATIVE: ![[MD_ivdep]] = !{!"llvm.loop.ivdep.safelen", i32 3}
32+
; CHECK-LLVM-NEGATIVE: ![[MD_unroll]] = !{!"llvm.loop.unroll.count", i32 2}
33+
34+
; ModuleID = 'intel-fpga-loops.cpp'
35+
source_filename = "intel-fpga-loops.cpp"
36+
target datalayout = "e-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-n8:16:32:64"
37+
target triple = "spir64-unknown-linux-sycldevice"
38+
39+
%class.anon = type { i8 }
40+
41+
; Function Attrs: nounwind
42+
define spir_func void @_Z4testv() #0 {
43+
entry:
44+
%a = alloca [10 x i32], align 4
45+
%i = alloca i32, align 4
46+
%0 = bitcast [10 x i32]* %a to i8*
47+
call void @llvm.lifetime.start.p0i8(i64 40, i8* %0) #4
48+
%1 = bitcast i32* %i to i8*
49+
call void @llvm.lifetime.start.p0i8(i64 4, i8* %1) #4
50+
store i32 0, i32* %i, align 4, !tbaa !2
51+
br label %for.cond
52+
53+
for.cond: ; preds = %for.inc, %entry
54+
%2 = load i32, i32* %i, align 4, !tbaa !2
55+
%cmp = icmp ne i32 %2, 10
56+
br i1 %cmp, label %for.body, label %for.cond.cleanup
57+
58+
for.cond.cleanup: ; preds = %for.cond
59+
%3 = bitcast i32* %i to i8*
60+
call void @llvm.lifetime.end.p0i8(i64 4, i8* %3) #4
61+
br label %for.end
62+
63+
for.body: ; preds = %for.cond
64+
%4 = load i32, i32* %i, align 4, !tbaa !2
65+
%idxprom = sext i32 %4 to i64
66+
%arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* %a, i64 0, i64 %idxprom, !llvm.index.group !6
67+
store i32 0, i32* %arrayidx, align 4, !tbaa !2
68+
br label %for.inc
69+
70+
for.inc: ; preds = %for.body
71+
%5 = load i32, i32* %i, align 4, !tbaa !2
72+
%inc = add nsw i32 %5, 1
73+
store i32 %inc, i32* %i, align 4, !tbaa !2
74+
br label %for.cond, !llvm.loop !7
75+
76+
for.end: ; preds = %for.cond.cleanup
77+
%6 = bitcast [10 x i32]* %a to i8*
78+
call void @llvm.lifetime.end.p0i8(i64 40, i8* %6) #4
79+
ret void
80+
}
81+
82+
; Function Attrs: argmemonly nounwind willreturn
83+
declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
84+
85+
; Function Attrs: argmemonly nounwind willreturn
86+
declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
87+
88+
; Function Attrs: norecurse nounwind
89+
define i32 @main() #2 {
90+
entry:
91+
%retval = alloca i32, align 4
92+
%agg.tmp = alloca %class.anon, align 1
93+
store i32 0, i32* %retval, align 4
94+
call spir_func void @"_Z18kernel_single_taskIZ4mainE15kernel_functionZ4mainE3$_0EvT0_"(%class.anon* byval(%class.anon) align 1 %agg.tmp)
95+
ret i32 0
96+
}
97+
98+
; Function Attrs: nounwind
99+
define internal spir_func void @"_Z18kernel_single_taskIZ4mainE15kernel_functionZ4mainE3$_0EvT0_"(%class.anon* byval(%class.anon) align 1 %kernelFunc) #0 {
100+
entry:
101+
%0 = addrspacecast %class.anon* %kernelFunc to %class.anon addrspace(4)*
102+
call spir_func void @"_ZZ4mainENK3$_0clEv"(%class.anon addrspace(4)* %0)
103+
ret void
104+
}
105+
106+
; Function Attrs: inlinehint nounwind
107+
define internal spir_func void @"_ZZ4mainENK3$_0clEv"(%class.anon addrspace(4)* %this) #3 align 2 {
108+
entry:
109+
%this.addr = alloca %class.anon addrspace(4)*, align 8
110+
store %class.anon addrspace(4)* %this, %class.anon addrspace(4)** %this.addr, align 8, !tbaa !13
111+
%this1 = load %class.anon addrspace(4)*, %class.anon addrspace(4)** %this.addr, align 8
112+
call spir_func void @_Z4testv()
113+
ret void
114+
}
115+
116+
attributes #0 = { nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
117+
attributes #1 = { argmemonly nounwind willreturn }
118+
attributes #2 = { norecurse nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
119+
attributes #3 = { inlinehint nounwind "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "frame-pointer"="none" "less-precise-fpmad"="false" "min-legal-vector-width"="0" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
120+
attributes #4 = { nounwind }
121+
122+
!llvm.module.flags = !{!0}
123+
!llvm.ident = !{!1}
124+
125+
!0 = !{i32 1, !"wchar_size", i32 4}
126+
!1 = !{!"clang version 12.0.0"}
127+
!2 = !{!3, !3, i64 0}
128+
!3 = !{!"int", !4, i64 0}
129+
!4 = !{!"omnipotent char", !5, i64 0}
130+
!5 = !{!"Simple C++ TBAA"}
131+
!6 = distinct !{}
132+
!7 = distinct !{!7, !8, !9, !10, !11, !12}
133+
!8 = !{!"llvm.loop.parallel_access_indices", !6, i32 3}
134+
!9 = !{!"llvm.loop.ivdep.safelen", i32 3}
135+
!10 = !{!"llvm.loop.ii.count", i32 1}
136+
!11 = !{!"llvm.loop.intel.speculated.iterations.count", i32 0}
137+
!12 = !{!"llvm.loop.unroll.count", i32 2}
138+
!13 = !{!14, !14, i64 0}
139+
!14 = !{!"any pointer", !4, i64 0}

0 commit comments

Comments
 (0)