LLVM 24.0.0git
ConcurrencySanitizer.cpp
Go to the documentation of this file.
1//===- ConcurrencySanitizer.cpp - watchpoint race detector ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements instrumentation for ConcurrencySanitizer, a sampling
10// data-race detector. Memory accesses are preceded by runtime probes while the
11// original operations remain unchanged.
12//
13//===----------------------------------------------------------------------===//
14
17#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/Statistic.h"
20#include "llvm/ADT/bit.h"
24#include "llvm/IR/DataLayout.h"
25#include "llvm/IR/IRBuilder.h"
28#include "llvm/IR/Intrinsics.h"
29#include "llvm/IR/Module.h"
40#include <optional>
41
42using namespace llvm;
43
44#define DEBUG_TYPE "csan"
45
47 "csan-instrument-memory-accesses", cl::init(true),
48 cl::desc("Instrument memory accesses"), cl::Hidden);
49static cl::opt<bool>
50 ClInstrumentFuncEntryExit("csan-instrument-func-entry-exit", cl::init(true),
51 cl::desc("Instrument function entry and exit"),
54 "csan-handle-cxx-exceptions", cl::init(true),
55 cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"),
57static cl::opt<bool> ClInstrumentAtomics("csan-instrument-atomics",
58 cl::init(true),
59 cl::desc("Instrument atomics"),
62 "csan-instrument-memintrinsics", cl::init(true),
63 cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden);
65 "csan-distinguish-volatile", cl::init(false),
66 cl::desc("Treat aligned volatile accesses up to 8 bytes as atomic"),
68STATISTIC(NumInstrumentedReads, "Number of instrumented reads");
69STATISTIC(NumInstrumentedWrites, "Number of instrumented writes");
70STATISTIC(NumOmittedReadsBeforeWrite,
71 "Number of reads ignored due to following writes");
72
73static constexpr char kCsanModuleCtorName[] = "csan.module_ctor";
74static constexpr char kCsanInitName[] = "__csan_init";
75
76// Accesses sizes are powers of two: 1, 2, 4, 8, 16.
77static constexpr size_t kNumAccessSizes = 5;
79 "__csan_read1", "__csan_read2", "__csan_read4", "__csan_read8",
80 "__csan_read16"};
82 "__csan_write1", "__csan_write2", "__csan_write4", "__csan_write8",
83 "__csan_write16"};
85 "__csan_unaligned_read1", "__csan_unaligned_read2",
86 "__csan_unaligned_read4", "__csan_unaligned_read8",
87 "__csan_unaligned_read16"};
89 "__csan_unaligned_write1", "__csan_unaligned_write2",
90 "__csan_unaligned_write4", "__csan_unaligned_write8",
91 "__csan_unaligned_write16"};
93 "__csan_read_write1", "__csan_read_write2", "__csan_read_write4",
94 "__csan_read_write8", "__csan_read_write16"};
96 {"__csan_unaligned_read_write1", "__csan_unaligned_read_write2",
97 "__csan_unaligned_read_write4", "__csan_unaligned_read_write8",
98 "__csan_unaligned_read_write16"};
99
100namespace {
101
102/// Must match CSAN_ACCESS_* in compiler-rt/lib/csan/csan_defs.h.
103enum class AccessFlags : unsigned {
104 None = 0,
105 Atomic = 1u << 0,
106 Compound = 1u << 1,
108};
109
110static bool isAtomicMemoryAccess(const Instruction *I) {
111 std::optional<SyncScope::ID> SSID = getAtomicSyncScopeID(I);
112 if (!SSID)
113 return false;
115 return *SSID != SyncScope::SingleThread;
116 return true;
117}
118
119static Value *getCallbackAddress(IRBuilderBase &IRB, Value *Addr) {
120 return IRB.CreateAddrSpaceCast(Addr, IRB.getPtrTy());
121}
122
124 return IRB.getInt32(static_cast<uint32_t>(toCABI(Ord)));
125}
126
127static int getAccessSizeIndex(Type *Ty, const DataLayout &DL) {
128 assert(Ty->isSized());
129 if (Ty->isScalableTy())
130 return -1;
131 uint32_t TypeSize = DL.getTypeStoreSizeInBits(Ty);
132 if (TypeSize != 8 && TypeSize != 16 && TypeSize != 32 && TypeSize != 64 &&
133 TypeSize != 128)
134 return -1;
135 unsigned Idx = llvm::countr_zero(TypeSize / 8);
136 return static_cast<int>(Idx);
137}
138
139// A later write of the same pointer drops an earlier read in this window.
140static void selectMemoryAccesses(SmallVectorImpl<Instruction *> &Local,
143 for (Instruction *Inst : reverse(Local)) {
144 Value *Addr = getLoadStorePointerOperand(Inst);
145 if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
146 WriteTargets[Addr] = Store;
147 Out.push_back(Inst);
148 continue;
149 }
150
151 // A volatile write is reported as atomic when distinguished, so it does
152 // not cover a plain read. Keep the read if either access is volatile.
153 StoreInst *LaterWrite = WriteTargets.lookup(Addr);
154 bool AnyVolatile =
155 LaterWrite && ClDistinguishVolatile &&
156 (cast<LoadInst>(Inst)->isVolatile() || LaterWrite->isVolatile());
157 if (LaterWrite && !AnyVolatile) {
158 ++NumOmittedReadsBeforeWrite;
159 continue;
160 }
161
162 Out.push_back(Inst);
163 }
164 Local.clear();
165}
166
167static bool addressSpaceMayRace(const Triple &T, unsigned AS) {
168 if (T.isAMDGPU()) {
169 // GDS and buffer fat pointers cannot form a generic watchpoint key.
170 return AS == AMDGPUAS::FLAT_ADDRESS || AS == AMDGPUAS::GLOBAL_ADDRESS ||
172 }
173 if (T.isNVPTX()) {
174 return AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
178 }
179 if (T.isSPIRV()) {
180 // FIXME: No exposed address spaces for SPIR-V.
181 return false;
182 }
183 return AS == 0;
184}
185
186struct ConcurrencySanitizer {
187 bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI);
188
189private:
190 struct MemoryAccessLists {
191 SmallVector<Instruction *, 8> LoadsAndStores;
192 SmallVector<Instruction *, 8> AtomicAccesses;
193 SmallVector<IntrinsicInst *, 8> MemIntrinCalls;
194 bool HasCalls = false;
195 };
196
197 void initialize(Module &M, const TargetLibraryInfo &TLI);
198 void collectMemoryAccesses(Function &F, MemoryAccessLists &Out);
199 bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
200 bool instrumentAtomic(Instruction *I, const DataLayout &DL);
201 bool instrumentMemIntrinsic(IntrinsicInst *II, const DataLayout &DL);
202 bool insertAccessProbe(Instruction *I, Value *Addr, Type *AccessTy,
203 const DataLayout &DL, bool IsWrite, bool IsCompound,
204 bool IsAtomic);
205 bool shouldInstrumentAddress(Value *Addr) const;
206 bool shouldInstrumentAccess(Instruction *I) const;
207 void insertFuncEntryExit(Function &F);
208 void insertRuntimeIgnores(Function &F);
209 Constant *getFlags(AccessFlags Flags) const {
210 return ConstantInt::get(FlagsTy, to_underlying(Flags));
211 }
212
213 Module *Mod = nullptr;
214 Type *IntptrTy = nullptr;
215 IntegerType *FlagsTy = nullptr;
216
217 // void __csan_readN(ptr, i32);
218 FunctionCallee CsanRead[kNumAccessSizes];
219 // void __csan_writeN(ptr, i32);
220 FunctionCallee CsanWrite[kNumAccessSizes];
221 // void __csan_unaligned_readN(ptr, i32);
222 FunctionCallee CsanUnalignedRead[kNumAccessSizes];
223 // void __csan_unaligned_writeN(ptr, i32);
224 FunctionCallee CsanUnalignedWrite[kNumAccessSizes];
225 // void __csan_read_writeN(ptr, i32);
226 FunctionCallee CsanCompoundRW[kNumAccessSizes];
227 // void __csan_unaligned_read_writeN(ptr, i32);
228 FunctionCallee CsanUnalignedCompoundRW[kNumAccessSizes];
229 // void __csan_func_entry(ptr);
230 FunctionCallee CsanFuncEntry;
231 // void __csan_func_exit();
232 FunctionCallee CsanFuncExit;
233 // void __csan_ignore_thread_begin();
234 FunctionCallee CsanIgnoreBegin;
235 // void __csan_ignore_thread_end();
236 FunctionCallee CsanIgnoreEnd;
237 // void __csan_read_range(ptr, intptr_t, i32);
238 FunctionCallee CsanReadRange;
239 // void __csan_write_range(ptr, intptr_t, i32);
240 FunctionCallee CsanWriteRange;
241 // void __csan_atomic_thread_fence(i32);
242 FunctionCallee CsanAtomicThreadFence;
243 // void __csan_atomic_signal_fence(i32);
244 FunctionCallee CsanAtomicSignalFence;
245};
246
247void insertModuleCtor(Module &M) {
249 M, kCsanModuleCtorName, kCsanInitName, /*InitArgTypes=*/{},
250 /*InitArgs=*/{},
251 [&](Function *Ctor, FunctionCallee) { appendToGlobalCtors(M, Ctor, 0); });
252}
253
254} // namespace
255
258 ConcurrencySanitizer CSan;
259 if (CSan.sanitizeFunction(F, FAM.getResult<TargetLibraryAnalysis>(F)))
261 return PreservedAnalyses::all();
262}
263
271
272void ConcurrencySanitizer::initialize(Module &M, const TargetLibraryInfo &TLI) {
273 LLVMContext &Ctx = M.getContext();
274 Mod = &M;
275 IntptrTy = M.getDataLayout().getIntPtrType(Ctx);
276 FlagsTy = Type::getInt32Ty(Ctx);
277
278 AttributeList Attr = AttributeList().addFnAttribute(Ctx, Attribute::NoUnwind);
279 IRBuilder<> IRB(M);
280 Type *VoidTy = IRB.getVoidTy();
281 Type *PtrTy = IRB.getPtrTy();
282 CsanFuncEntry =
283 M.getOrInsertFunction("__csan_func_entry", Attr, VoidTy, PtrTy);
284 CsanFuncExit = M.getOrInsertFunction("__csan_func_exit", Attr, VoidTy);
285 CsanIgnoreBegin =
286 M.getOrInsertFunction("__csan_ignore_thread_begin", Attr, VoidTy);
287 CsanIgnoreEnd =
288 M.getOrInsertFunction("__csan_ignore_thread_end", Attr, VoidTy);
289 auto AccessFn = [&](StringRef Name) {
290 return M.getOrInsertFunction(Name, Attr, VoidTy, PtrTy, FlagsTy);
291 };
292 for (unsigned I = 0; I < kNumAccessSizes; ++I) {
293 CsanRead[I] = AccessFn(kCsanReadNames[I]);
294 CsanWrite[I] = AccessFn(kCsanWriteNames[I]);
295 CsanUnalignedRead[I] = AccessFn(kCsanUnalignedReadNames[I]);
296 CsanUnalignedWrite[I] = AccessFn(kCsanUnalignedWriteNames[I]);
297 CsanCompoundRW[I] = AccessFn(kCsanCompoundRWNames[I]);
298 CsanUnalignedCompoundRW[I] = AccessFn(kCsanUnalignedCompoundRWNames[I]);
299 }
300 IntegerType *OrdTy = IRB.getInt32Ty();
301 CsanReadRange = M.getOrInsertFunction("__csan_read_range", Attr, VoidTy,
302 PtrTy, IntptrTy, FlagsTy);
303 CsanWriteRange = M.getOrInsertFunction("__csan_write_range", Attr, VoidTy,
304 PtrTy, IntptrTy, FlagsTy);
305 CsanAtomicThreadFence = M.getOrInsertFunction(
306 "__csan_atomic_thread_fence",
307 TLI.getAttrList(&Ctx, {0}, /*Signed=*/true, /*Ret=*/false, Attr), VoidTy,
308 OrdTy);
309 CsanAtomicSignalFence = M.getOrInsertFunction(
310 "__csan_atomic_signal_fence",
311 TLI.getAttrList(&Ctx, {0}, /*Signed=*/true, /*Ret=*/false, Attr), VoidTy,
312 OrdTy);
313}
314
315bool ConcurrencySanitizer::sanitizeFunction(Function &F,
316 const TargetLibraryInfo &TLI) {
317 // This is required to prevent instrumenting call to __csan_init from within
318 // the module constructor.
319 if (F.getName() == kCsanModuleCtorName)
320 return false;
321 // Naked functions can not have prologue/epilogue
322 // (__csan_func_entry/__csan_func_exit) generated, so don't instrument them at
323 // all.
324 if (F.hasFnAttribute(Attribute::Naked))
325 return false;
326
327 // __attribute__(disable_sanitizer_instrumentation) prevents all kinds of
328 // instrumentation.
329 if (F.hasFnAttribute(Attribute::DisableSanitizerInstrumentation))
330 return false;
331
332 Mod = F.getParent();
333 MemoryAccessLists Acc;
334 collectMemoryAccesses(F, Acc);
335
336 const bool SuppressChecking =
337 F.hasFnAttribute("sanitize_concurrency_no_checking_at_run_time");
338 const bool SanitizeFunction =
339 F.hasFnAttribute(Attribute::SanitizeConcurrency) && !SuppressChecking;
340 const bool MayInstrument =
341 SanitizeFunction &&
342 ((ClInstrumentMemoryAccesses && !Acc.LoadsAndStores.empty()) ||
343 (ClInstrumentAtomics && !Acc.AtomicAccesses.empty()) ||
344 (ClInstrumentMemIntrinsics && !Acc.MemIntrinCalls.empty()));
345 const bool NeedsRuntimeIgnores = SuppressChecking && Acc.HasCalls;
346 const bool NeedsFuncEntryExit = ClInstrumentFuncEntryExit && Acc.HasCalls;
347 if (!MayInstrument && !NeedsRuntimeIgnores && !NeedsFuncEntryExit)
348 return false;
349
350 initialize(*Mod, TLI);
351 bool Res = false;
352 const DataLayout &DL = F.getDataLayout();
353
354 if (ClInstrumentMemoryAccesses && SanitizeFunction)
355 for (Instruction *I : Acc.LoadsAndStores)
356 Res |= instrumentLoadOrStore(I, DL);
357
358 if (ClInstrumentAtomics && SanitizeFunction)
359 for (Instruction *I : Acc.AtomicAccesses)
360 Res |= instrumentAtomic(I, DL);
361
362 if (ClInstrumentMemIntrinsics && SanitizeFunction)
363 for (IntrinsicInst *II : Acc.MemIntrinCalls)
364 Res |= instrumentMemIntrinsic(II, DL);
365
366 if (NeedsRuntimeIgnores) {
367 insertRuntimeIgnores(F);
368 Res = true;
369 }
370
371 if ((Res || Acc.HasCalls) && ClInstrumentFuncEntryExit) {
372 insertFuncEntryExit(F);
373 Res = true;
374 }
375 return Res;
376}
377
378bool ConcurrencySanitizer::shouldInstrumentAddress(Value *Addr) const {
380 if (auto *GV = dyn_cast<GlobalVariable>(BaseAddr)) {
381 if (GV->hasSection()) {
382 StringRef SectionName = GV->getSection();
383 Triple::ObjectFormatType OF = Mod->getTargetTriple().getObjectFormat();
384 if (SectionName.ends_with(
385 getInstrProfSectionName(IPSK_cnts, OF, /*AddSegmentInfo=*/false)))
386 return false;
387 }
388 }
389
390 Type *PtrTy = cast<PointerType>(Addr->getType()->getScalarType());
391 unsigned AS = PtrTy->getPointerAddressSpace();
392 if (Mod->getDataLayout().getPointerSizeInBits(AS) > 64)
393 return false;
394 return addressSpaceMayRace(Mod->getTargetTriple(), AS);
395}
396
397bool ConcurrencySanitizer::shouldInstrumentAccess(Instruction *I) const {
398 const bool IsWrite = isa<StoreInst>(I);
400 if (!shouldInstrumentAddress(Addr))
401 return false;
402
403 if (!IsWrite)
404 if (auto *GV = dyn_cast<GlobalVariable>(getUnderlyingObject(Addr)))
405 if (GV->isConstant())
406 return false;
407
408 const AllocaInst *AI = findAllocaForValue(Addr);
409 if (!AI || PointerMayBeCaptured(AI, /*ReturnCaptures=*/true))
410 return true;
411
412 const Triple &T = AI->getModule()->getTargetTriple();
413 return T.isGPU() && addressSpaceMayRace(T, AI->getAddressSpace());
414}
415
416void ConcurrencySanitizer::collectMemoryAccesses(Function &F,
417 MemoryAccessLists &Out) {
418 SmallVector<Instruction *, 8> LocalLoadsAndStores;
419
420 for (BasicBlock &BB : F) {
421 for (Instruction &Inst : BB) {
422 // Skip instructions inserted by another instrumentation.
423 if (Inst.hasMetadata(LLVMContext::MD_nosanitize))
424 continue;
425 if (isAtomicMemoryAccess(&Inst))
426 Out.AtomicAccesses.push_back(&Inst);
427 else if ((isa<LoadInst>(Inst) || isa<StoreInst>(Inst)) &&
428 shouldInstrumentAccess(&Inst))
429 LocalLoadsAndStores.push_back(&Inst);
430 else if (isa<CallBase>(Inst)) {
432 Out.MemIntrinCalls.push_back(cast<IntrinsicInst>(&Inst));
433 Out.HasCalls = true;
434 selectMemoryAccesses(LocalLoadsAndStores, Out.LoadsAndStores);
435 }
436 }
437 selectMemoryAccesses(LocalLoadsAndStores, Out.LoadsAndStores);
438 }
439}
440
441bool ConcurrencySanitizer::instrumentLoadOrStore(Instruction *I,
442 const DataLayout &DL) {
443 const bool IsWrite = isa<StoreInst>(I);
445 if (!insertAccessProbe(I, Addr, getLoadStoreType(I), DL, IsWrite,
446 /*IsCompound=*/false, /*IsAtomic=*/false))
447 return false;
448 if (IsWrite)
449 ++NumInstrumentedWrites;
450 else
451 ++NumInstrumentedReads;
452 return true;
453}
454
455bool ConcurrencySanitizer::instrumentAtomic(Instruction *I,
456 const DataLayout &DL) {
457 if (auto *FI = dyn_cast<FenceInst>(I)) {
459 FunctionCallee Fn = FI->getSyncScopeID() == SyncScope::SingleThread
460 ? CsanAtomicSignalFence
461 : CsanAtomicThreadFence;
462 IRB.CreateCall(Fn, createOrdering(IRB, FI->getOrdering()));
463 return true;
464 }
465
466 Value *Addr = nullptr;
467 Type *AccessTy = nullptr;
468 bool IsWrite = true;
469 bool IsCompound = false;
470 if (auto *LI = dyn_cast<LoadInst>(I)) {
471 Addr = LI->getPointerOperand();
472 AccessTy = LI->getType();
473 IsWrite = false;
474 } else if (auto *SI = dyn_cast<StoreInst>(I)) {
475 Addr = SI->getPointerOperand();
476 AccessTy = SI->getValueOperand()->getType();
477 } else if (auto *RMW = dyn_cast<AtomicRMWInst>(I)) {
478 Addr = RMW->getPointerOperand();
479 AccessTy = RMW->getValOperand()->getType();
480 IsCompound = true;
481 } else if (auto *CAS = dyn_cast<AtomicCmpXchgInst>(I)) {
482 // A failed CAS is still considered a write as the output is unkonwn.
483 Addr = CAS->getPointerOperand();
484 AccessTy = CAS->getNewValOperand()->getType();
485 IsCompound = true;
486 } else {
487 return false;
488 }
489
490 if (!shouldInstrumentAddress(Addr))
491 return false;
492 if (!insertAccessProbe(I, Addr, AccessTy, DL, IsWrite, IsCompound,
493 /*IsAtomic=*/true))
494 return false;
495 if (IsCompound || IsWrite)
496 ++NumInstrumentedWrites;
497 if (IsCompound || !IsWrite)
498 ++NumInstrumentedReads;
499 return true;
500}
501
502bool ConcurrencySanitizer::instrumentMemIntrinsic(IntrinsicInst *II,
503 const DataLayout &DL) {
505 auto *MSP = dyn_cast<MemSetPatternInst>(II);
506 Value *Dst = MI ? MI->getRawDest() : MSP->getRawDest();
507 Value *Src = nullptr;
508 if (auto *MT = dyn_cast<AnyMemTransferInst>(II))
509 Src = MT->getRawSource();
510
511 bool InstrumentRead = Src && shouldInstrumentAddress(Src);
512 bool InstrumentWrite = shouldInstrumentAddress(Dst);
513 if (!InstrumentRead && !InstrumentWrite)
514 return false;
515
517 Value *Len = IRB.CreateIntCast(MI ? MI->getLength() : MSP->getLength(),
518 IntptrTy, false);
519 // The length of a pattern memset counts patterns, not bytes.
520 if (MSP) {
521 TypeSize Size = DL.getTypeAllocSize(MSP->getValue()->getType());
522 Len = IRB.CreateMul(Len, IRB.CreateTypeSize(IntptrTy, Size));
523 }
524 Constant *Flags =
525 getFlags(MI && MI->isAtomic() ? AccessFlags::Atomic : AccessFlags::None);
526 if (InstrumentRead) {
527 IRB.CreateCall(CsanReadRange, {getCallbackAddress(IRB, Src), Len, Flags});
528 ++NumInstrumentedReads;
529 }
530 if (InstrumentWrite) {
531 IRB.CreateCall(CsanWriteRange, {getCallbackAddress(IRB, Dst), Len, Flags});
532 ++NumInstrumentedWrites;
533 }
534 return true;
535}
536
537bool ConcurrencySanitizer::insertAccessProbe(Instruction *I, Value *Addr,
538 Type *AccessTy,
539 const DataLayout &DL, bool IsWrite,
540 bool IsCompound, bool IsAtomic) {
541 if (Addr->isSwiftError())
542 return false;
543 AccessFlags Flags = AccessFlags::None;
544 if (IsAtomic)
545 Flags |= AccessFlags::Atomic;
546 if (IsCompound)
547 Flags |= AccessFlags::Compound;
548 int Idx = getAccessSizeIndex(AccessTy, DL);
549 if (Idx < 0) {
550 if (IsCompound)
551 return false;
553 Value *Len = IRB.CreateTypeSize(IntptrTy, DL.getTypeStoreSize(AccessTy));
554 IRB.CreateCall(IsWrite ? CsanWriteRange : CsanReadRange,
555 {getCallbackAddress(IRB, Addr), Len, getFlags(Flags)});
556 return true;
557 }
558
559 Align Alignment = Align(1);
560 bool IsVolatile = false;
561 if (auto *LI = dyn_cast<LoadInst>(I)) {
562 Alignment = LI->getAlign();
563 IsVolatile = LI->isVolatile();
564 } else if (auto *SI = dyn_cast<StoreInst>(I)) {
565 Alignment = SI->getAlign();
566 IsVolatile = SI->isVolatile();
567 } else if (auto *RMW = dyn_cast<AtomicRMWInst>(I)) {
568 Alignment = RMW->getAlign();
569 IsVolatile = RMW->isVolatile();
570 } else if (auto *CAS = dyn_cast<AtomicCmpXchgInst>(I)) {
571 Alignment = CAS->getAlign();
572 IsVolatile = CAS->isVolatile();
573 }
574
575 uint32_t TypeSize = DL.getTypeStoreSizeInBits(AccessTy);
576 bool Unaligned =
577 Alignment < Align(8) && Alignment.value() % (TypeSize / 8) != 0;
579 if (IsCompound)
580 Callback = Unaligned ? CsanUnalignedCompoundRW[Idx] : CsanCompoundRW[Idx];
581 else if (Unaligned)
582 Callback = IsWrite ? CsanUnalignedWrite[Idx] : CsanUnalignedRead[Idx];
583 else
584 Callback = IsWrite ? CsanWrite[Idx] : CsanRead[Idx];
585
587 Value *CallbackAddr = getCallbackAddress(IRB, Addr);
588 Value *FlagsVal = getFlags(Flags);
589 if (ClDistinguishVolatile && IsVolatile && TypeSize <= 64) {
590 // The declared alignment may understate the pointer's real alignment.
591 Value *IsAligned = IRB.getTrue();
592 if (Unaligned)
593 IsAligned = IRB.CreateIsNull(IRB.CreateAnd(
594 IRB.CreatePtrToInt(CallbackAddr, IntptrTy), TypeSize / 8 - 1));
595 FlagsVal = IRB.CreateSelect(
596 IsAligned, getFlags(Flags | AccessFlags::Atomic), FlagsVal);
597 }
598 IRB.CreateCall(Callback, {CallbackAddr, FlagsVal});
599 return true;
600}
601
602void ConcurrencySanitizer::insertFuncEntryExit(Function &F) {
603 const DataLayout &DL = F.getDataLayout();
604 InstrumentationIRBuilder IRB(&*F.getEntryBlock().getFirstNonPHIIt());
605 Type *ProgramAsPtrTy =
606 PointerType::get(F.getContext(), DL.getProgramAddressSpace());
607 Value *ReturnAddress = IRB.CreateIntrinsic(Intrinsic::returnaddress,
608 {ProgramAsPtrTy}, IRB.getInt32(0));
609 IRB.CreateCall(CsanFuncEntry, ReturnAddress);
610
611 EscapeEnumerator EE(F, "csan_cleanup", ClHandleCxxExceptions);
612 while (IRBuilder<> *AtExit = EE.Next()) {
614 AtExit->CreateCall(CsanFuncExit);
615 }
616}
617
618void ConcurrencySanitizer::insertRuntimeIgnores(Function &F) {
619 InstrumentationIRBuilder IRB(&*F.getEntryBlock().getFirstNonPHIIt());
620 IRB.CreateCall(CsanIgnoreBegin);
621 EscapeEnumerator EE(F, "csan_ignore_cleanup", ClHandleCxxExceptions);
622 while (IRBuilder<> *AtExit = EE.Next()) {
624 AtExit->CreateCall(CsanIgnoreEnd);
625 }
626}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Atomic ordering constants.
static cl::opt< bool > ClInstrumentAtomics("csan-instrument-atomics", cl::init(true), cl::desc("Instrument atomics"), cl::Hidden)
static constexpr StringLiteral kCsanUnalignedReadNames[kNumAccessSizes]
static cl::opt< bool > ClInstrumentMemoryAccesses("csan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden)
static constexpr StringLiteral kCsanWriteNames[kNumAccessSizes]
static constexpr StringLiteral kCsanReadNames[kNumAccessSizes]
static cl::opt< bool > ClDistinguishVolatile("csan-distinguish-volatile", cl::init(false), cl::desc("Treat aligned volatile accesses up to 8 bytes as atomic"), cl::Hidden)
static constexpr size_t kNumAccessSizes
static cl::opt< bool > ClInstrumentMemIntrinsics("csan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden)
static constexpr StringLiteral kCsanUnalignedCompoundRWNames[kNumAccessSizes]
static cl::opt< bool > ClHandleCxxExceptions("csan-handle-cxx-exceptions", cl::init(true), cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"), cl::Hidden)
static constexpr StringLiteral kCsanCompoundRWNames[kNumAccessSizes]
static constexpr StringLiteral kCsanUnalignedWriteNames[kNumAccessSizes]
static cl::opt< bool > ClInstrumentFuncEntryExit("csan-instrument-func-entry-exit", cl::init(true), cl::desc("Instrument function entry and exit"), cl::Hidden)
static constexpr char kCsanInitName[]
static constexpr char kCsanModuleCtorName[]
static bool insertModuleCtor(Module &M)
Definition CopyProf.cpp:77
This file defines the DenseMap class.
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
NVPTX address space definition.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
static uint32_t getFlags(const Symbol *Sym)
Definition TapiFile.cpp:26
static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, const llvm::StringTable &StandardNames, VectorLibrary VecLib)
Initialize the set of available library functions based on the specified target triple.
static ConstantInt * createOrdering(IRBuilder<> *IRB, AtomicOrdering ord)
This file implements the C++20 <bit> header.
an instruction to allocate memory on the stack
unsigned getAddressSpace() const
Return the address space for the allocation.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
This is the shared class of boolean and integer constants.
Definition Constants.h:87
This is an important base class in LLVM.
Definition Constant.h:44
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
Definition DenseMap.h:793
EscapeEnumerator - This is a little algorithm to find all escape points from a function so that "fina...
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
Common base class shared among various IRBuilders.
Definition IRBuilder.h:111
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNull=false)
Definition IRBuilder.h:2248
ConstantInt * getTrue()
Get the constant value for i1 true.
Definition IRBuilder.h:445
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition IRBuilder.h:522
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition IRBuilder.h:465
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:1566
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2233
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2561
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:565
LLVM_ABI Value * CreateTypeSize(Type *Ty, TypeSize Size)
Create an expression which evaluates to the number of units in Size at runtime.
Value * CreateIntCast(Value *V, Type *DestTy, bool isSigned, const Twine &Name="")
Definition IRBuilder.h:2323
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
Definition IRBuilder.h:2758
Type * getVoidTy()
Fetch the type representing void.
Definition IRBuilder.h:560
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1452
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
Class to represent integer types.
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
Definition Module.h:328
static LLVM_ABI PointerType * get(LLVMContext &C, unsigned AddressSpace)
This constructs an opaque pointer to an object in a numbered address space.
Definition Type.cpp:887
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
bool isVolatile() const
Return true if this is a store to a volatile memory location.
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:888
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Analysis pass providing the TargetLibraryInfo.
Provides information about what library functions are available for the current target.
AttributeList getAttrList(LLVMContext *C, ArrayRef< unsigned > ArgNos, bool Signed, bool Ret=false, AttributeList AL=AttributeList()) const
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:363
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI const Value * stripInBoundsOffsets(function_ref< void(const Value *)> Func=[](const Value *) {}) const
Strip off pointer casts and inbounds GEPs.
Definition Value.cpp:824
LLVM_ABI bool isSwiftError() const
Return true if this value is a swifterror value.
Definition Value.cpp:1145
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
constexpr char IsVolatile[]
Key for Kernel::Arg::Metadata::mIsVolatile.
@ SingleThread
Synchronized with respect to signal handlers executing in the same thread.
Definition LLVMContext.h:63
initializer< Ty > init(const Ty &Val)
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition Transport.h:132
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI AllocaInst * findAllocaForValue(Value *V, bool OffsetZero=false)
Returns unique alloca where the value comes from, or nullptr.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
const Value * getLoadStorePointerOperand(const Value *V)
A helper function that returns the pointer operand of a load or store instruction.
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI std::string getInstrProfSectionName(InstrProfSectKind IPSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Return the name of the profile section corresponding to IPSK.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
int countr_zero(T Val)
Count number of 0's from the least significant bit to the most stopping at the first 1.
Definition bit.h:204
AtomicOrderingCABI toCABI(AtomicOrdering AO)
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
LLVM_ABI std::pair< Function *, FunctionCallee > getOrCreateSanitizerCtorAndInitFunctions(Module &M, StringRef CtorName, StringRef InitName, ArrayRef< Type * > InitArgTypes, ArrayRef< Value * > InitArgs, function_ref< void(Function *, FunctionCallee)> FunctionsCreatedCallback, StringRef VersionCheckName=StringRef(), bool Weak=false)
Creates sanitizer constructor function lazily.
std::optional< SyncScope::ID > getAtomicSyncScopeID(const Instruction *I)
A helper function that returns an atomic operation's sync scope; returns std::nullopt if it is not an...
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth, bool MustPreserveProvenance=false)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ Mod
The access may modify the value stored in memory.
Definition ModRef.h:34
LLVM_ABI bool PointerMayBeCaptured(const Value *V, bool ReturnCaptures, unsigned MaxUsesToExplore=0)
PointerMayBeCaptured - Return true if this pointer value may be captured by the enclosing function (w...
LLVM_ABI void appendToGlobalCtors(Module &M, Function *F, int Priority, Constant *Data=nullptr)
Append F to the list of global ctors of module M with the given Priority.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Type * getLoadStoreType(const Value *I)
A helper function that returns the type of a load or store instruction.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool checkIfAlreadyInstrumented(Module &M, StringRef Flag)
Check if module has flag attached, if not add the flag.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM)
static void ensureDebugInfo(IRBuilder<> &IRB, const Function &F)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)