Skip to content

Commit 37370ca

Browse files
thurstonddvbuka
authored andcommitted
[msan] Convert target("aarch64.svcount") from compile-time crash to MSan false negatives (llvm#165028)
MSan currently crashes at compile-time when it encounters target("aarch64.svcount") (e.g., llvm#164315). This patch duct-tapes MSan so that it won't crash at compile-time, and instead propagates a clean shadow (resulting in false negatives but not false positives).
1 parent 706a775 commit 37370ca

File tree

5 files changed

+621
-14
lines changed

5 files changed

+621
-14
lines changed

llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ static const Align kMinOriginAlignment = Align(4);
226226
static const Align kShadowTLSAlignment = Align(8);
227227

228228
// These constants must be kept in sync with the ones in msan.h.
229+
// TODO: increase size to match SVE/SVE2/SME/SME2 limits
229230
static const unsigned kParamTLSSize = 800;
230231
static const unsigned kRetvalTLSSize = 800;
231232

@@ -1544,6 +1545,22 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
15441545
}
15451546
}
15461547

1548+
static bool isAArch64SVCount(Type *Ty) {
1549+
if (TargetExtType *TTy = dyn_cast<TargetExtType>(Ty))
1550+
return TTy->getName() == "aarch64.svcount";
1551+
return false;
1552+
}
1553+
1554+
// This is intended to match the "AArch64 Predicate-as-Counter Type" (aka
1555+
// 'target("aarch64.svcount")', but not e.g., <vscale x 4 x i32>.
1556+
static bool isScalableNonVectorType(Type *Ty) {
1557+
if (!isAArch64SVCount(Ty))
1558+
LLVM_DEBUG(dbgs() << "isScalableNonVectorType: Unexpected type " << *Ty
1559+
<< "\n");
1560+
1561+
return Ty->isScalableTy() && !isa<VectorType>(Ty);
1562+
}
1563+
15471564
void materializeChecks() {
15481565
#ifndef NDEBUG
15491566
// For assert below.
@@ -1672,6 +1689,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
16721689
LLVM_DEBUG(dbgs() << "getShadowTy: " << *ST << " ===> " << *Res << "\n");
16731690
return Res;
16741691
}
1692+
if (isScalableNonVectorType(OrigTy)) {
1693+
LLVM_DEBUG(dbgs() << "getShadowTy: Scalable non-vector type: " << *OrigTy
1694+
<< "\n");
1695+
return OrigTy;
1696+
}
1697+
16751698
uint32_t TypeSize = DL.getTypeSizeInBits(OrigTy);
16761699
return IntegerType::get(*MS.C, TypeSize);
16771700
}
@@ -2185,8 +2208,14 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
21852208
<< *OrigIns << "\n");
21862209
return;
21872210
}
2188-
#ifndef NDEBUG
2211+
21892212
Type *ShadowTy = Shadow->getType();
2213+
if (isScalableNonVectorType(ShadowTy)) {
2214+
LLVM_DEBUG(dbgs() << "Skipping check of scalable non-vector " << *Shadow
2215+
<< " before " << *OrigIns << "\n");
2216+
return;
2217+
}
2218+
#ifndef NDEBUG
21902219
assert((isa<IntegerType>(ShadowTy) || isa<VectorType>(ShadowTy) ||
21912220
isa<StructType>(ShadowTy) || isa<ArrayType>(ShadowTy)) &&
21922221
"Can only insert checks for integer, vector, and aggregate shadow "
@@ -6972,6 +7001,15 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
69727001
// an extra "select". This results in much more compact IR.
69737002
// Sa = select Sb, poisoned, (select b, Sc, Sd)
69747003
Sa1 = getPoisonedShadow(getShadowTy(I.getType()));
7004+
} else if (isScalableNonVectorType(I.getType())) {
7005+
// This is intended to handle target("aarch64.svcount"), which can't be
7006+
// handled in the else branch because of incompatibility with CreateXor
7007+
// ("The supported LLVM operations on this type are limited to load,
7008+
// store, phi, select and alloca instructions").
7009+
7010+
// TODO: this currently underapproximates. Use Arm SVE EOR in the else
7011+
// branch as needed instead.
7012+
Sa1 = getCleanShadow(getShadowTy(I.getType()));
69757013
} else {
69767014
// Sa = select Sb, [ (c^d) | Sc | Sd ], [ b ? Sc : Sd ]
69777015
// If Sb (condition is poisoned), look for bits in c and d that are equal
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt -S -passes=msan -mattr=+sme -o - %s
3-
4-
; XFAIL: *
2+
; RUN: opt -S -passes=msan -mattr=+sme -o - %s | FileCheck %s
53

64
; Forked from llvm/test/CodeGen/AArch64/sme-aarch64-svcount.ll
7-
; Manually minimized to show MSan leads to a compiler crash
85

96
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
107
target triple = "aarch64--linux-android9001"
118

129
define target("aarch64.svcount") @test_return_arg1(target("aarch64.svcount") %arg0, target("aarch64.svcount") %arg1) nounwind {
10+
; CHECK-LABEL: @test_return_arg1(
11+
; CHECK-NEXT: call void @llvm.donothing()
12+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr @__msan_retval_tls, align 8
13+
; CHECK-NEXT: ret target("aarch64.svcount") [[ARG1:%.*]]
14+
;
1315
ret target("aarch64.svcount") %arg1
1416
}

llvm/test/Instrumentation/MemorySanitizer/AArch64/sme-aarch64-svcount.ll

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt -S -passes=msan -mattr=+sme -o - %s
3-
4-
; XFAIL: *
2+
; RUN: opt -S -passes=msan -mattr=+sme -o - %s | FileCheck %s
53

64
; Forked from llvm/test/CodeGen/AArch64/sme-aarch64-svcount.ll
75

@@ -12,16 +10,49 @@ target triple = "aarch64--linux-android9001"
1210
; Test simple loads, stores and return.
1311
;
1412
define target("aarch64.svcount") @test_load(ptr %ptr) nounwind {
13+
; CHECK-LABEL: @test_load(
14+
; CHECK-NEXT: call void @llvm.donothing()
15+
; CHECK-NEXT: [[RES:%.*]] = load target("aarch64.svcount"), ptr [[PTR:%.*]], align 2
16+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr @__msan_retval_tls, align 8
17+
; CHECK-NEXT: ret target("aarch64.svcount") [[RES]]
18+
;
1519
%res = load target("aarch64.svcount"), ptr %ptr
1620
ret target("aarch64.svcount") %res
1721
}
1822

1923
define void @test_store(ptr %ptr, target("aarch64.svcount") %val) nounwind {
24+
; CHECK-LABEL: @test_store(
25+
; CHECK-NEXT: call void @llvm.donothing()
26+
; CHECK-NEXT: [[TMP1:%.*]] = ptrtoint ptr [[PTR:%.*]] to i64
27+
; CHECK-NEXT: [[TMP2:%.*]] = xor i64 [[TMP1]], 193514046488576
28+
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to ptr
29+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr [[TMP3]], align 2
30+
; CHECK-NEXT: store target("aarch64.svcount") [[VAL:%.*]], ptr [[PTR]], align 2
31+
; CHECK-NEXT: ret void
32+
;
2033
store target("aarch64.svcount") %val, ptr %ptr
2134
ret void
2235
}
2336

2437
define target("aarch64.svcount") @test_alloca_store_reload(target("aarch64.svcount") %val) nounwind {
38+
; CHECK-LABEL: @test_alloca_store_reload(
39+
; CHECK-NEXT: call void @llvm.donothing()
40+
; CHECK-NEXT: [[PTR:%.*]] = alloca target("aarch64.svcount"), align 1
41+
; CHECK-NEXT: [[TMP1:%.*]] = call i64 @llvm.vscale.i64()
42+
; CHECK-NEXT: [[TMP2:%.*]] = mul nuw i64 [[TMP1]], 2
43+
; CHECK-NEXT: [[TMP3:%.*]] = ptrtoint ptr [[PTR]] to i64
44+
; CHECK-NEXT: [[TMP4:%.*]] = xor i64 [[TMP3]], 193514046488576
45+
; CHECK-NEXT: [[TMP5:%.*]] = inttoptr i64 [[TMP4]] to ptr
46+
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 1 [[TMP5]], i8 0, i64 [[TMP2]], i1 false)
47+
; CHECK-NEXT: [[TMP6:%.*]] = ptrtoint ptr [[PTR]] to i64
48+
; CHECK-NEXT: [[TMP7:%.*]] = xor i64 [[TMP6]], 193514046488576
49+
; CHECK-NEXT: [[TMP8:%.*]] = inttoptr i64 [[TMP7]] to ptr
50+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr [[TMP8]], align 2
51+
; CHECK-NEXT: store target("aarch64.svcount") [[VAL:%.*]], ptr [[PTR]], align 2
52+
; CHECK-NEXT: [[RES:%.*]] = load target("aarch64.svcount"), ptr [[PTR]], align 2
53+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr @__msan_retval_tls, align 8
54+
; CHECK-NEXT: ret target("aarch64.svcount") [[RES]]
55+
;
2556
%ptr = alloca target("aarch64.svcount"), align 1
2657
store target("aarch64.svcount") %val, ptr %ptr
2758
%res = load target("aarch64.svcount"), ptr %ptr
@@ -33,10 +64,20 @@ define target("aarch64.svcount") @test_alloca_store_reload(target("aarch64.svcou
3364
;
3465

3566
define target("aarch64.svcount") @test_return_arg1(target("aarch64.svcount") %arg0, target("aarch64.svcount") %arg1) nounwind {
67+
; CHECK-LABEL: @test_return_arg1(
68+
; CHECK-NEXT: call void @llvm.donothing()
69+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr @__msan_retval_tls, align 8
70+
; CHECK-NEXT: ret target("aarch64.svcount") [[ARG1:%.*]]
71+
;
3672
ret target("aarch64.svcount") %arg1
3773
}
3874

3975
define target("aarch64.svcount") @test_return_arg4(target("aarch64.svcount") %arg0, target("aarch64.svcount") %arg1, target("aarch64.svcount") %arg2, target("aarch64.svcount") %arg3, target("aarch64.svcount") %arg4) nounwind {
76+
; CHECK-LABEL: @test_return_arg4(
77+
; CHECK-NEXT: call void @llvm.donothing()
78+
; CHECK-NEXT: store target("aarch64.svcount") zeroinitializer, ptr @__msan_retval_tls, align 8
79+
; CHECK-NEXT: ret target("aarch64.svcount") [[ARG4:%.*]]
80+
;
4081
ret target("aarch64.svcount") %arg4
4182
}
4283

@@ -46,22 +87,58 @@ define target("aarch64.svcount") @test_return_arg4(target("aarch64.svcount") %ar
4687

4788
declare void @take_svcount_1(target("aarch64.svcount") %arg)
4889
define void @test_pass_1arg(target("aarch64.svcount") %arg) nounwind {
90+
; CHECK-LABEL: @test_pass_1arg(
91+
; CHECK-NEXT: call void @llvm.donothing()
92+
; CHECK-NEXT: call void @take_svcount_1(target("aarch64.svcount") [[ARG:%.*]])
93+
; CHECK-NEXT: ret void
94+
;
4995
call void @take_svcount_1(target("aarch64.svcount") %arg)
5096
ret void
5197
}
5298

5399
declare void @take_svcount_5(target("aarch64.svcount") %arg0, target("aarch64.svcount") %arg1, target("aarch64.svcount") %arg2, target("aarch64.svcount") %arg3, target("aarch64.svcount") %arg4)
54100
define void @test_pass_5args(target("aarch64.svcount") %arg) nounwind {
101+
; CHECK-LABEL: @test_pass_5args(
102+
; CHECK-NEXT: call void @llvm.donothing()
103+
; CHECK-NEXT: call void @take_svcount_5(target("aarch64.svcount") [[ARG:%.*]], target("aarch64.svcount") [[ARG]], target("aarch64.svcount") [[ARG]], target("aarch64.svcount") [[ARG]], target("aarch64.svcount") [[ARG]])
104+
; CHECK-NEXT: ret void
105+
;
55106
call void @take_svcount_5(target("aarch64.svcount") %arg, target("aarch64.svcount") %arg, target("aarch64.svcount") %arg, target("aarch64.svcount") %arg, target("aarch64.svcount") %arg)
56107
ret void
57108
}
58109

59110
define target("aarch64.svcount") @test_sel(target("aarch64.svcount") %x, target("aarch64.svcount") %y, i1 %cmp) sanitize_memory {
111+
; CHECK-LABEL: @test_sel(
112+
; CHECK-NEXT: [[TMP1:%.*]] = load i1, ptr @__msan_param_tls, align 8
113+
; CHECK-NEXT: call void @llvm.donothing()
114+
; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[CMP:%.*]], target("aarch64.svcount") zeroinitializer, target("aarch64.svcount") zeroinitializer
115+
; CHECK-NEXT: [[_MSPROP_SELECT:%.*]] = select i1 [[TMP1]], target("aarch64.svcount") zeroinitializer, target("aarch64.svcount") [[TMP2]]
116+
; CHECK-NEXT: [[X_Y:%.*]] = select i1 [[CMP]], target("aarch64.svcount") [[X:%.*]], target("aarch64.svcount") [[Y:%.*]]
117+
; CHECK-NEXT: store target("aarch64.svcount") [[_MSPROP_SELECT]], ptr @__msan_retval_tls, align 8
118+
; CHECK-NEXT: ret target("aarch64.svcount") [[X_Y]]
119+
;
60120
%x.y = select i1 %cmp, target("aarch64.svcount") %x, target("aarch64.svcount") %y
61121
ret target("aarch64.svcount") %x.y
62122
}
63123

64124
define target("aarch64.svcount") @test_sel_cc(target("aarch64.svcount") %x, target("aarch64.svcount") %y, i32 %k) sanitize_memory {
125+
; CHECK-LABEL: @test_sel_cc(
126+
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr @__msan_param_tls, align 8
127+
; CHECK-NEXT: call void @llvm.donothing()
128+
; CHECK-NEXT: [[TMP2:%.*]] = xor i32 [[K:%.*]], -2147483648
129+
; CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP1]], -1
130+
; CHECK-NEXT: [[TMP4:%.*]] = and i32 [[TMP2]], [[TMP3]]
131+
; CHECK-NEXT: [[TMP5:%.*]] = or i32 [[TMP2]], [[TMP1]]
132+
; CHECK-NEXT: [[TMP6:%.*]] = icmp ugt i32 [[TMP4]], -2147483606
133+
; CHECK-NEXT: [[TMP7:%.*]] = icmp ugt i32 [[TMP5]], -2147483606
134+
; CHECK-NEXT: [[TMP8:%.*]] = xor i1 [[TMP6]], [[TMP7]]
135+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[K]], 42
136+
; CHECK-NEXT: [[TMP9:%.*]] = select i1 [[CMP]], target("aarch64.svcount") zeroinitializer, target("aarch64.svcount") zeroinitializer
137+
; CHECK-NEXT: [[_MSPROP_SELECT:%.*]] = select i1 [[TMP8]], target("aarch64.svcount") zeroinitializer, target("aarch64.svcount") [[TMP9]]
138+
; CHECK-NEXT: [[X_Y:%.*]] = select i1 [[CMP]], target("aarch64.svcount") [[X:%.*]], target("aarch64.svcount") [[Y:%.*]]
139+
; CHECK-NEXT: store target("aarch64.svcount") [[_MSPROP_SELECT]], ptr @__msan_retval_tls, align 8
140+
; CHECK-NEXT: ret target("aarch64.svcount") [[X_Y]]
141+
;
65142
%cmp = icmp sgt i32 %k, 42
66143
%x.y = select i1 %cmp, target("aarch64.svcount") %x, target("aarch64.svcount") %y
67144
ret target("aarch64.svcount") %x.y

llvm/test/Instrumentation/MemorySanitizer/AArch64/sme2-intrinsics-add-mini.ll

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2-
; RUN: opt -S -passes=msan -mattr=+sme2 -mattr=+sme-i16i64 -mattr=+sme-f64f64 -o - %s
3-
4-
; XFAIL: *
2+
; RUN: opt -S -passes=msan -mattr=+sme2 -mattr=+sme-i16i64 -mattr=+sme-f64f64 -o - %s | FileCheck %s
53

64
; Forked from llvm/test/CodeGen/AArch64/sme2-intrinsics-add.ll
75
; Manually reduced to show MSan leads to a compiler crash
@@ -10,6 +8,19 @@ target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
108
target triple = "aarch64--linux-android9001"
119

1210
define void @multi_vector_add_za_vg1x4_f32_tuple(i64 %stride, ptr %ptr) sanitize_memory {
11+
; CHECK-LABEL: @multi_vector_add_za_vg1x4_f32_tuple(
12+
; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr getelementptr (i8, ptr @__msan_param_tls, i64 8), align 8
13+
; CHECK-NEXT: call void @llvm.donothing()
14+
; CHECK-NEXT: [[TMP2:%.*]] = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c8()
15+
; CHECK-NEXT: [[_MSCMP:%.*]] = icmp ne i64 [[TMP1]], 0
16+
; CHECK-NEXT: br i1 [[_MSCMP]], label [[TMP3:%.*]], label [[TMP4:%.*]], !prof [[PROF1:![0-9]+]]
17+
; CHECK: 3:
18+
; CHECK-NEXT: call void @__msan_warning_noreturn() #[[ATTR5:[0-9]+]]
19+
; CHECK-NEXT: unreachable
20+
; CHECK: 4:
21+
; CHECK-NEXT: [[TMP5:%.*]] = tail call { <vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float> } @llvm.aarch64.sve.ld1.pn.x4.nxv4f32(target("aarch64.svcount") [[TMP2]], ptr [[PTR:%.*]])
22+
; CHECK-NEXT: ret void
23+
;
1324
%1 = tail call target("aarch64.svcount") @llvm.aarch64.sve.ptrue.c8()
1425
%2 = tail call { <vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float>, <vscale x 4 x float> } @llvm.aarch64.sve.ld1.pn.x4.nxv4f32(target("aarch64.svcount") %1, ptr %ptr)
1526
ret void

0 commit comments

Comments
 (0)