Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 752e143

Browse files
committed
[tsan] Add support for pointer typed atomic stores, loads, and cmpxchg
TSan instrumentation functions for atomic stores, loads, and cmpxchg work on integer value types. This patch adds casts before calling TSan instrumentation functions in cases where the value is a pointer. Differential Revision: http://reviews.llvm.org/D17833 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@262876 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 28c54ab commit 752e143

File tree

2 files changed

+66
-8
lines changed

2 files changed

+66
-8
lines changed

lib/Transforms/Instrumentation/ThreadSanitizer.cpp

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -520,6 +520,11 @@ bool ThreadSanitizer::instrumentMemIntrinsic(Instruction *I) {
520520
return false;
521521
}
522522

523+
static Value *createIntOrPtrToIntCast(Value *V, Type* Ty, IRBuilder<> &IRB) {
524+
return isa<PointerType>(V->getType()) ?
525+
IRB.CreatePtrToInt(V, Ty) : IRB.CreateIntCast(V, Ty, false);
526+
}
527+
523528
// Both llvm and ThreadSanitizer atomic operations are based on C++11/C1x
524529
// standards. For background see C++11 standard. A slightly older, publicly
525530
// available draft of the standard (not entirely up-to-date, but close enough
@@ -541,9 +546,16 @@ bool ThreadSanitizer::instrumentAtomic(Instruction *I, const DataLayout &DL) {
541546
Type *PtrTy = Ty->getPointerTo();
542547
Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
543548
createOrdering(&IRB, LI->getOrdering())};
544-
CallInst *C = CallInst::Create(TsanAtomicLoad[Idx], Args);
545-
ReplaceInstWithInst(I, C);
546-
549+
Type *OrigTy = cast<PointerType>(Addr->getType())->getElementType();
550+
if (Ty == OrigTy) {
551+
Instruction *C = CallInst::Create(TsanAtomicLoad[Idx], Args);
552+
ReplaceInstWithInst(I, C);
553+
} else {
554+
// We are loading a pointer, so we need to cast the return value.
555+
Value *C = IRB.CreateCall(TsanAtomicLoad[Idx], Args);
556+
Instruction *Cast = CastInst::Create(Instruction::IntToPtr, C, OrigTy);
557+
ReplaceInstWithInst(I, Cast);
558+
}
547559
} else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
548560
Value *Addr = SI->getPointerOperand();
549561
int Idx = getMemoryAccessFuncIndex(Addr, DL);
@@ -554,7 +566,7 @@ bool ThreadSanitizer::instrumentAtomic(Instruction *I, const DataLayout &DL) {
554566
Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
555567
Type *PtrTy = Ty->getPointerTo();
556568
Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
557-
IRB.CreateIntCast(SI->getValueOperand(), Ty, false),
569+
createIntOrPtrToIntCast(SI->getValueOperand(), Ty, IRB),
558570
createOrdering(&IRB, SI->getOrdering())};
559571
CallInst *C = CallInst::Create(TsanAtomicStore[Idx], Args);
560572
ReplaceInstWithInst(I, C);
@@ -584,15 +596,26 @@ bool ThreadSanitizer::instrumentAtomic(Instruction *I, const DataLayout &DL) {
584596
const unsigned BitSize = ByteSize * 8;
585597
Type *Ty = Type::getIntNTy(IRB.getContext(), BitSize);
586598
Type *PtrTy = Ty->getPointerTo();
599+
Value *CmpOperand =
600+
createIntOrPtrToIntCast(CASI->getCompareOperand(), Ty, IRB);
601+
Value *NewOperand =
602+
createIntOrPtrToIntCast(CASI->getNewValOperand(), Ty, IRB);
587603
Value *Args[] = {IRB.CreatePointerCast(Addr, PtrTy),
588-
IRB.CreateIntCast(CASI->getCompareOperand(), Ty, false),
589-
IRB.CreateIntCast(CASI->getNewValOperand(), Ty, false),
604+
CmpOperand,
605+
NewOperand,
590606
createOrdering(&IRB, CASI->getSuccessOrdering()),
591607
createOrdering(&IRB, CASI->getFailureOrdering())};
592608
CallInst *C = IRB.CreateCall(TsanAtomicCAS[Idx], Args);
593-
Value *Success = IRB.CreateICmpEQ(C, CASI->getCompareOperand());
609+
Value *Success = IRB.CreateICmpEQ(C, CmpOperand);
610+
Value *OldVal = C;
611+
Type *OrigOldValTy = CASI->getNewValOperand()->getType();
612+
if (Ty != OrigOldValTy) {
613+
// The value is a pointer, so we need to cast the return value.
614+
OldVal = IRB.CreateIntToPtr(C, OrigOldValTy);
615+
}
594616

595-
Value *Res = IRB.CreateInsertValue(UndefValue::get(CASI->getType()), C, 0);
617+
Value *Res =
618+
IRB.CreateInsertValue(UndefValue::get(CASI->getType()), OldVal, 0);
596619
Res = IRB.CreateInsertValue(Res, Success, 1);
597620

598621
I->replaceAllUsesWith(Res);

test/Instrumentation/ThreadSanitizer/atomic.ll

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,16 @@ entry:
11861186
; CHECK-LABEL: atomic64_load_seq_cst
11871187
; CHECK: call i64 @__tsan_atomic64_load(i64* %a, i32 5), !dbg
11881188

1189+
define i8* @atomic64_load_seq_cst_ptr_ty(i8** %a) nounwind uwtable {
1190+
entry:
1191+
%0 = load atomic i8*, i8** %a seq_cst, align 8, !dbg !7
1192+
ret i8* %0, !dbg !7
1193+
}
1194+
; CHECK-LABEL: atomic64_load_seq_cst
1195+
; CHECK: bitcast i8** %{{.+}} to i64*
1196+
; CHECK-NEXT: call i64 @__tsan_atomic64_load(i64* %{{.+}}, i32 5), !dbg
1197+
; CHECK-NEXT: inttoptr i64 %{{.+}} to i8*
1198+
11891199
define void @atomic64_store_unordered(i64* %a) nounwind uwtable {
11901200
entry:
11911201
store atomic i64 0, i64* %a unordered, align 8, !dbg !7
@@ -1218,6 +1228,16 @@ entry:
12181228
; CHECK-LABEL: atomic64_store_seq_cst
12191229
; CHECK: call void @__tsan_atomic64_store(i64* %a, i64 0, i32 5), !dbg
12201230

1231+
define void @atomic64_store_seq_cst_ptr_ty(i8** %a, i8* %v) nounwind uwtable {
1232+
entry:
1233+
store atomic i8* %v, i8** %a seq_cst, align 8, !dbg !7
1234+
ret void, !dbg !7
1235+
}
1236+
; CHECK-LABEL: atomic64_store_seq_cst
1237+
; CHECK: %{{.*}} = bitcast i8** %{{.*}} to i64*
1238+
; CHECK-NEXT: %{{.*}} = ptrtoint i8* %{{.*}} to i64
1239+
; CHECK-NEXT: call void @__tsan_atomic64_store(i64* %{{.*}}, i64 %{{.*}}, i32 5), !dbg
1240+
12211241
define void @atomic64_xchg_monotonic(i64* %a) nounwind uwtable {
12221242
entry:
12231243
atomicrmw xchg i64* %a, i64 0 monotonic, !dbg !7
@@ -1538,6 +1558,21 @@ entry:
15381558
; CHECK-LABEL: atomic64_cas_seq_cst
15391559
; CHECK: call i64 @__tsan_atomic64_compare_exchange_val(i64* %a, i64 0, i64 1, i32 5, i32 5), !dbg
15401560

1561+
define void @atomic64_cas_seq_cst_ptr_ty(i8** %a, i8* %v1, i8* %v2) nounwind uwtable {
1562+
entry:
1563+
cmpxchg i8** %a, i8* %v1, i8* %v2 seq_cst seq_cst, !dbg !7
1564+
ret void
1565+
}
1566+
; CHECK-LABEL: atomic64_cas_seq_cst
1567+
; CHECK: {{.*}} = ptrtoint i8* %v1 to i64
1568+
; CHECK-NEXT: {{.*}} = ptrtoint i8* %v2 to i64
1569+
; CHECK-NEXT: {{.*}} = bitcast i8** %a to i64*
1570+
; CHECK-NEXT: {{.*}} = call i64 @__tsan_atomic64_compare_exchange_val(i64* {{.*}}, i64 {{.*}}, i64 {{.*}}, i32 5, i32 5), !dbg
1571+
; CHECK-NEXT: {{.*}} = icmp eq i64
1572+
; CHECK-NEXT: {{.*}} = inttoptr i64 {{.*}} to i8*
1573+
; CHECK-NEXT: {{.*}} = insertvalue { i8*, i1 } undef, i8* {{.*}}, 0
1574+
; CHECK-NEXT: {{.*}} = insertvalue { i8*, i1 } {{.*}}, i1 {{.*}}, 1
1575+
15411576
define i128 @atomic128_load_unordered(i128* %a) nounwind uwtable {
15421577
entry:
15431578
%0 = load atomic i128, i128* %a unordered, align 16, !dbg !7

0 commit comments

Comments
 (0)