Skip to content

Commit 31bfa4a

Browse files
committed
[MSAN] Add handleCountZeroes for ctlz and cttz.
This addresses a bug where vector versions of ctlz are creating false positive reports. Depends on D136369 Reviewed By: vitalybuka Differential Revision: https://reviews.llvm.org/D136523
1 parent 6faf40b commit 31bfa4a

File tree

2 files changed

+61
-64
lines changed

2 files changed

+61
-64
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2970,6 +2970,27 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
29702970
setOrigin(&I, getOrigin(Op));
29712971
}
29722972

2973+
void handleCountZeroes(IntrinsicInst &I) {
2974+
IRBuilder<> IRB(&I);
2975+
Value *Src = I.getArgOperand(0);
2976+
2977+
// Set the Output shadow based on input Shadow
2978+
Value *BoolShadow = IRB.CreateIsNotNull(getShadow(Src), "_mscz_bs");
2979+
2980+
// If zero poison is requested, mix in with the shadow
2981+
Constant *IsZeroPoison = cast<Constant>(I.getOperand(1));
2982+
if (!IsZeroPoison->isZeroValue()) {
2983+
Value *BoolZeroPoison = IRB.CreateIsNull(Src, "_mscz_bzp");
2984+
BoolShadow = IRB.CreateOr(BoolShadow, BoolZeroPoison, "_mscz_bs");
2985+
}
2986+
2987+
Value *OutputShadow =
2988+
IRB.CreateSExt(BoolShadow, getShadowTy(Src), "_mscz_os");
2989+
2990+
setShadow(&I, OutputShadow);
2991+
setOriginForNaryOp(I);
2992+
}
2993+
29732994
// Instrument vector convert intrinsic.
29742995
//
29752996
// This function instruments intrinsics like cvtsi2ss:
@@ -3651,6 +3672,10 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
36513672
case Intrinsic::bswap:
36523673
handleBswap(I);
36533674
break;
3675+
case Intrinsic::ctlz:
3676+
case Intrinsic::cttz:
3677+
handleCountZeroes(I);
3678+
break;
36543679
case Intrinsic::masked_compressstore:
36553680
handleMaskedCompressStore(I);
36563681
break;

llvm/test/Instrumentation/MemorySanitizer/count-zeroes.ll

Lines changed: 36 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ define i64 @test_ctlz_i64_zeropoison(i64 %v) #0 {
99
; CHECK-LABEL: @test_ctlz_i64_zeropoison(
1010
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
1111
; CHECK-NEXT: call void @llvm.donothing()
12-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
13-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP2:%.*]], label [[TMP3:%.*]], !prof [[PROF0:![0-9]+]]
14-
; CHECK: 2:
15-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4:[0-9]+]]
16-
; CHECK-NEXT: unreachable
17-
; CHECK: 3:
18-
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.ctlz.i64(i64 [[V:%.*]], i1 true)
19-
; CHECK-NEXT: store i64 0, ptr @__msan_retval_tls, align 8
12+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne i64 [[TMP1]], 0
13+
; CHECK-NEXT: [[_MSCZ_BZP:%.*]] = icmp eq i64 [[V:%.*]], 0
14+
; CHECK-NEXT: [[_MSCZ_BS1:%.*]] = or i1 [[_MSCZ_BS]], [[_MSCZ_BZP]]
15+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext i1 [[_MSCZ_BS1]] to i64
16+
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.ctlz.i64(i64 [[V]], i1 true)
17+
; CHECK-NEXT: store i64 [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
2018
; CHECK-NEXT: ret i64 [[RES]]
2119
;
2220
%res = call i64 @llvm.ctlz.i64(i64 %v, i1 true) ; <<i64>> [#uses=1]
@@ -26,14 +24,10 @@ define i64 @test_ctlz_i64_nozeropoison(i64 %v) #0 {
2624
; CHECK-LABEL: @test_ctlz_i64_nozeropoison(
2725
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
2826
; CHECK-NEXT: call void @llvm.donothing()
29-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
30-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP2:%.*]], label [[TMP3:%.*]], !prof [[PROF0]]
31-
; CHECK: 2:
32-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
33-
; CHECK-NEXT: unreachable
34-
; CHECK: 3:
27+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne i64 [[TMP1]], 0
28+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext i1 [[_MSCZ_BS]] to i64
3529
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.ctlz.i64(i64 [[V:%.*]], i1 false)
36-
; CHECK-NEXT: store i64 0, ptr @__msan_retval_tls, align 8
30+
; CHECK-NEXT: store i64 [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
3731
; CHECK-NEXT: ret i64 [[RES]]
3832
;
3933
%res = call i64 @llvm.ctlz.i64(i64 %v, i1 false) ; <<i64>> [#uses=1]
@@ -45,15 +39,12 @@ define <2 x i64> @test_ctlz_v2i64_zeropoison(<2 x i64> %v) #0 {
4539
; CHECK-LABEL: @test_ctlz_v2i64_zeropoison(
4640
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, ptr @__msan_param_tls, align 8
4741
; CHECK-NEXT: call void @llvm.donothing()
48-
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP1]] to i128
49-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP2]], 0
50-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP3:%.*]], label [[TMP4:%.*]], !prof [[PROF0]]
51-
; CHECK: 3:
52-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
53-
; CHECK-NEXT: unreachable
54-
; CHECK: 4:
55-
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> [[V:%.*]], i1 true)
56-
; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr @__msan_retval_tls, align 8
42+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne <2 x i64> [[TMP1]], zeroinitializer
43+
; CHECK-NEXT: [[_MSCZ_BZP:%.*]] = icmp eq <2 x i64> [[V:%.*]], zeroinitializer
44+
; CHECK-NEXT: [[_MSCZ_BS1:%.*]] = or <2 x i1> [[_MSCZ_BS]], [[_MSCZ_BZP]]
45+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext <2 x i1> [[_MSCZ_BS1]] to <2 x i64>
46+
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> [[V]], i1 true)
47+
; CHECK-NEXT: store <2 x i64> [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
5748
; CHECK-NEXT: ret <2 x i64> [[RES]]
5849
;
5950
%res = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %v, i1 true) ; <<2 x i64>> [#uses=1]
@@ -63,15 +54,10 @@ define <2 x i64> @test_ctlz_v2i64_nozeropoison(<2 x i64> %v) #0 {
6354
; CHECK-LABEL: @test_ctlz_v2i64_nozeropoison(
6455
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, ptr @__msan_param_tls, align 8
6556
; CHECK-NEXT: call void @llvm.donothing()
66-
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP1]] to i128
67-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP2]], 0
68-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP3:%.*]], label [[TMP4:%.*]], !prof [[PROF0]]
69-
; CHECK: 3:
70-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
71-
; CHECK-NEXT: unreachable
72-
; CHECK: 4:
57+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne <2 x i64> [[TMP1]], zeroinitializer
58+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext <2 x i1> [[_MSCZ_BS]] to <2 x i64>
7359
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> [[V:%.*]], i1 false)
74-
; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr @__msan_retval_tls, align 8
60+
; CHECK-NEXT: store <2 x i64> [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
7561
; CHECK-NEXT: ret <2 x i64> [[RES]]
7662
;
7763
%res = call <2 x i64> @llvm.ctlz.v2i64(<2 x i64> %v, i1 false) ; <<2 x i64>> [#uses=1]
@@ -83,14 +69,12 @@ define i64 @test_cttz_i64_zeropoison(i64 %v) #0 {
8369
; CHECK-LABEL: @test_cttz_i64_zeropoison(
8470
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
8571
; CHECK-NEXT: call void @llvm.donothing()
86-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
87-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP2:%.*]], label [[TMP3:%.*]], !prof [[PROF0]]
88-
; CHECK: 2:
89-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
90-
; CHECK-NEXT: unreachable
91-
; CHECK: 3:
92-
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.cttz.i64(i64 [[V:%.*]], i1 true)
93-
; CHECK-NEXT: store i64 0, ptr @__msan_retval_tls, align 8
72+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne i64 [[TMP1]], 0
73+
; CHECK-NEXT: [[_MSCZ_BZP:%.*]] = icmp eq i64 [[V:%.*]], 0
74+
; CHECK-NEXT: [[_MSCZ_BS1:%.*]] = or i1 [[_MSCZ_BS]], [[_MSCZ_BZP]]
75+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext i1 [[_MSCZ_BS1]] to i64
76+
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.cttz.i64(i64 [[V]], i1 true)
77+
; CHECK-NEXT: store i64 [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
9478
; CHECK-NEXT: ret i64 [[RES]]
9579
;
9680
%res = call i64 @llvm.cttz.i64(i64 %v, i1 true) ; <<i64>> [#uses=1]
@@ -100,14 +84,10 @@ define i64 @test_cttz_i64_nozeropoison(i64 %v) #0 {
10084
; CHECK-LABEL: @test_cttz_i64_nozeropoison(
10185
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
10286
; CHECK-NEXT: call void @llvm.donothing()
103-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
104-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP2:%.*]], label [[TMP3:%.*]], !prof [[PROF0]]
105-
; CHECK: 2:
106-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
107-
; CHECK-NEXT: unreachable
108-
; CHECK: 3:
87+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne i64 [[TMP1]], 0
88+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext i1 [[_MSCZ_BS]] to i64
10989
; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.cttz.i64(i64 [[V:%.*]], i1 false)
110-
; CHECK-NEXT: store i64 0, ptr @__msan_retval_tls, align 8
90+
; CHECK-NEXT: store i64 [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
11191
; CHECK-NEXT: ret i64 [[RES]]
11292
;
11393
%res = call i64 @llvm.cttz.i64(i64 %v, i1 false) ; <<i64>> [#uses=1]
@@ -119,15 +99,12 @@ define <2 x i64> @test_cttz_v2i64_zeropoison(<2 x i64> %v) #0 {
11999
; CHECK-LABEL: @test_cttz_v2i64_zeropoison(
120100
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, ptr @__msan_param_tls, align 8
121101
; CHECK-NEXT: call void @llvm.donothing()
122-
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP1]] to i128
123-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP2]], 0
124-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP3:%.*]], label [[TMP4:%.*]], !prof [[PROF0]]
125-
; CHECK: 3:
126-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
127-
; CHECK-NEXT: unreachable
128-
; CHECK: 4:
129-
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> [[V:%.*]], i1 true)
130-
; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr @__msan_retval_tls, align 8
102+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne <2 x i64> [[TMP1]], zeroinitializer
103+
; CHECK-NEXT: [[_MSCZ_BZP:%.*]] = icmp eq <2 x i64> [[V:%.*]], zeroinitializer
104+
; CHECK-NEXT: [[_MSCZ_BS1:%.*]] = or <2 x i1> [[_MSCZ_BS]], [[_MSCZ_BZP]]
105+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext <2 x i1> [[_MSCZ_BS1]] to <2 x i64>
106+
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> [[V]], i1 true)
107+
; CHECK-NEXT: store <2 x i64> [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
131108
; CHECK-NEXT: ret <2 x i64> [[RES]]
132109
;
133110
%res = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> %v, i1 true) ; <<2 x i64>> [#uses=1]
@@ -137,15 +114,10 @@ define <2 x i64> @test_cttz_v2i64_nozeropoison(<2 x i64> %v) #0 {
137114
; CHECK-LABEL: @test_cttz_v2i64_nozeropoison(
138115
; CHECK-NEXT: [[TMP1:%.*]] = load <2 x i64>, ptr @__msan_param_tls, align 8
139116
; CHECK-NEXT: call void @llvm.donothing()
140-
; CHECK-NEXT: [[TMP2:%.*]] = bitcast <2 x i64> [[TMP1]] to i128
141-
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i128 [[TMP2]], 0
142-
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP3:%.*]], label [[TMP4:%.*]], !prof [[PROF0]]
143-
; CHECK: 3:
144-
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR4]]
145-
; CHECK-NEXT: unreachable
146-
; CHECK: 4:
117+
; CHECK-NEXT: [[_MSCZ_BS:%.*]] = icmp ne <2 x i64> [[TMP1]], zeroinitializer
118+
; CHECK-NEXT: [[_MSCZ_OS:%.*]] = sext <2 x i1> [[_MSCZ_BS]] to <2 x i64>
147119
; CHECK-NEXT: [[RES:%.*]] = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> [[V:%.*]], i1 false)
148-
; CHECK-NEXT: store <2 x i64> zeroinitializer, ptr @__msan_retval_tls, align 8
120+
; CHECK-NEXT: store <2 x i64> [[_MSCZ_OS]], ptr @__msan_retval_tls, align 8
149121
; CHECK-NEXT: ret <2 x i64> [[RES]]
150122
;
151123
%res = call <2 x i64> @llvm.cttz.v2i64(<2 x i64> %v, i1 false) ; <<2 x i64>> [#uses=1]

0 commit comments

Comments
 (0)