Skip to content

Commit 5d734fa

Browse files
authored
[llvm][SPIRV] Expose fast popcnt support for SPIR-V targets (#109845)
This adds the TTI predicate for conveying the availability of fast `popcnt`, which subsequently allows passes like `LoopIdiomRecognize` to collapse known popcount patterns. Since SPIR-V natively exposes `OpBitcount`, it seems preferable to compress the resulting code, and retain the information, even if a concrete target might have to expand back into a loop structure.
1 parent d48777e commit 5d734fa

File tree

3 files changed

+118
-0
lines changed

3 files changed

+118
-0
lines changed

llvm/lib/Target/SPIRV/SPIRVTargetTransformInfo.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
namespace llvm {
2525
class SPIRVTTIImpl : public BasicTTIImplBase<SPIRVTTIImpl> {
2626
using BaseT = BasicTTIImplBase<SPIRVTTIImpl>;
27+
using TTI = TargetTransformInfo;
2728

2829
friend BaseT;
2930

@@ -37,6 +38,16 @@ class SPIRVTTIImpl : public BasicTTIImplBase<SPIRVTTIImpl> {
3738
explicit SPIRVTTIImpl(const SPIRVTargetMachine *TM, const Function &F)
3839
: BaseT(TM, F.getDataLayout()), ST(TM->getSubtargetImpl(F)),
3940
TLI(ST->getTargetLowering()) {}
41+
42+
TTI::PopcntSupportKind getPopcntSupport(unsigned TyWidth) {
43+
// SPIR-V natively supports OpBitcount, per 3.53.14 in the spec, as such it
44+
// is reasonable to assume the Op is fast / preferable to the expanded loop.
45+
// Furthermore, this prevents information being lost if transforms are
46+
// applied to SPIR-V before lowering to a concrete target.
47+
if (!isPowerOf2_32(TyWidth) || TyWidth > 64)
48+
return TTI::PSK_Software; // Arbitrary bit-width INT is not core SPIR-V.
49+
return TTI::PSK_FastHardware;
50+
}
4051
};
4152

4253
} // namespace llvm
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
if not "SPIRV" in config.root.targets:
2+
config.unsupported = True
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
; RUN: opt -passes=loop-idiom -mtriple=spirv32-- -S < %s | FileCheck %s
2+
; RUN: opt -passes=loop-idiom -mtriple=spirv64-- -S < %s | FileCheck %s
3+
4+
; Mostly copied from x86 version.
5+
6+
;To recognize this pattern:
7+
;int popcount(unsigned long long a) {
8+
; int c = 0;
9+
; while (a) {
10+
; c++;
11+
; a &= a - 1;
12+
; }
13+
; return c;
14+
;}
15+
;
16+
17+
; CHECK-LABEL: @popcount_i64
18+
; CHECK: entry
19+
; CHECK: llvm.ctpop.i64
20+
; CHECK: ret
21+
define i32 @popcount_i64(i64 %a) nounwind uwtable readnone ssp {
22+
entry:
23+
%tobool3 = icmp eq i64 %a, 0
24+
br i1 %tobool3, label %while.end, label %while.body
25+
26+
while.body: ; preds = %entry, %while.body
27+
%c.05 = phi i32 [ %inc, %while.body ], [ 0, %entry ]
28+
%a.addr.04 = phi i64 [ %and, %while.body ], [ %a, %entry ]
29+
%inc = add nsw i32 %c.05, 1
30+
%sub = add i64 %a.addr.04, -1
31+
%and = and i64 %sub, %a.addr.04
32+
%tobool = icmp eq i64 %and, 0
33+
br i1 %tobool, label %while.end, label %while.body
34+
35+
while.end: ; preds = %while.body, %entry
36+
%c.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.body ]
37+
ret i32 %c.0.lcssa
38+
}
39+
40+
; CHECK-LABEL: @popcount_i32
41+
; CHECK: entry
42+
; CHECK: llvm.ctpop.i32
43+
; CHECK: ret
44+
define i32 @popcount_i32(i32 %a) nounwind uwtable readnone ssp {
45+
entry:
46+
%tobool3 = icmp eq i32 %a, 0
47+
br i1 %tobool3, label %while.end, label %while.body
48+
49+
while.body: ; preds = %entry, %while.body
50+
%c.05 = phi i32 [ %inc, %while.body ], [ 0, %entry ]
51+
%a.addr.04 = phi i32 [ %and, %while.body ], [ %a, %entry ]
52+
%inc = add nsw i32 %c.05, 1
53+
%sub = add i32 %a.addr.04, -1
54+
%and = and i32 %sub, %a.addr.04
55+
%tobool = icmp eq i32 %and, 0
56+
br i1 %tobool, label %while.end, label %while.body
57+
58+
while.end: ; preds = %while.body, %entry
59+
%c.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.body ]
60+
ret i32 %c.0.lcssa
61+
}
62+
63+
; To recognize this pattern:
64+
;int popcount(unsigned long long a, int mydata1, int mydata2) {
65+
; int c = 0;
66+
; while (a) {
67+
; c++;
68+
; a &= a - 1;
69+
; mydata1 *= c;
70+
; mydata2 *= (int)a;
71+
; }
72+
; return c + mydata1 + mydata2;
73+
;}
74+
75+
; CHECK-LABEL: @popcount2
76+
; CHECK: entry
77+
; CHECK: llvm.ctpop.i64
78+
; CHECK: ret
79+
define i32 @popcount2(i64 %a, i32 %mydata1, i32 %mydata2) nounwind uwtable readnone ssp {
80+
entry:
81+
%tobool9 = icmp eq i64 %a, 0
82+
br i1 %tobool9, label %while.end, label %while.body
83+
84+
while.body: ; preds = %entry, %while.body
85+
%c.013 = phi i32 [ %inc, %while.body ], [ 0, %entry ]
86+
%mydata2.addr.012 = phi i32 [ %mul1, %while.body ], [ %mydata2, %entry ]
87+
%mydata1.addr.011 = phi i32 [ %mul, %while.body ], [ %mydata1, %entry ]
88+
%a.addr.010 = phi i64 [ %and, %while.body ], [ %a, %entry ]
89+
%inc = add nsw i32 %c.013, 1
90+
%sub = add i64 %a.addr.010, -1
91+
%and = and i64 %sub, %a.addr.010
92+
%mul = mul nsw i32 %inc, %mydata1.addr.011
93+
%conv = trunc i64 %and to i32
94+
%mul1 = mul nsw i32 %conv, %mydata2.addr.012
95+
%tobool = icmp eq i64 %and, 0
96+
br i1 %tobool, label %while.end, label %while.body
97+
98+
while.end: ; preds = %while.body, %entry
99+
%c.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.body ]
100+
%mydata2.addr.0.lcssa = phi i32 [ %mydata2, %entry ], [ %mul1, %while.body ]
101+
%mydata1.addr.0.lcssa = phi i32 [ %mydata1, %entry ], [ %mul, %while.body ]
102+
%add = add i32 %mydata2.addr.0.lcssa, %mydata1.addr.0.lcssa
103+
%add2 = add i32 %add, %c.0.lcssa
104+
ret i32 %add2
105+
}

0 commit comments

Comments
 (0)