@@ -118,13 +118,19 @@ struct ThreadSanitizerOnSpirv {
118118
119119 void initialize ();
120120
121- void instrumentKernelsMetadata ();
121+ void instrumentModule ();
122122
123123 void appendDebugInfoToArgs (Instruction *I, SmallVectorImpl<Value *> &Args);
124124
125125private:
126+ void instrumentGlobalVariables ();
127+
128+ void instrumentKernelsMetadata ();
129+
126130 bool isSupportedSPIRKernel (Function &F);
127131
132+ bool isUnsupportedDeviceGlobal (const GlobalVariable &G);
133+
128134 GlobalVariable *GetOrCreateGlobalString (StringRef Name, StringRef Value,
129135 unsigned AddressSpace);
130136
@@ -243,7 +249,7 @@ PreservedAnalyses ModuleThreadSanitizerPass::run(Module &M,
243249 return PreservedAnalyses::all ();
244250 if (Triple (M.getTargetTriple ()).isSPIROrSPIRV ()) {
245251 ThreadSanitizerOnSpirv Spirv (M);
246- Spirv.instrumentKernelsMetadata ();
252+ Spirv.instrumentModule ();
247253 } else
248254 insertModuleCtor (M);
249255 return PreservedAnalyses::none ();
@@ -327,6 +333,70 @@ bool ThreadSanitizerOnSpirv::isSupportedSPIRKernel(Function &F) {
327333 return true ;
328334}
329335
336+ bool ThreadSanitizerOnSpirv::isUnsupportedDeviceGlobal (
337+ const GlobalVariable &G) {
338+ if (G.user_empty ())
339+ return true ;
340+ // Skip instrumenting on "__TsanKernelMetadata" etc.
341+ if (G.getName ().starts_with (" __Tsan" ))
342+ return true ;
343+ if (G.getName ().starts_with (" __tsan_" ))
344+ return true ;
345+ if (G.getName ().starts_with (" __spirv_BuiltIn" ))
346+ return true ;
347+ if (G.getName ().starts_with (" __usid_str" ))
348+ return true ;
349+ // TODO: Will support global variable with local address space later.
350+ if (G.getAddressSpace () == kSpirOffloadLocalAS )
351+ return true ;
352+ // Global variables have constant value or constant address space will not
353+ // trigger race condition.
354+ if (G.isConstant () || G.getAddressSpace () == kSpirOffloadConstantAS )
355+ return true ;
356+ return false ;
357+ }
358+
359+ void ThreadSanitizerOnSpirv::instrumentModule () {
360+ instrumentGlobalVariables ();
361+ instrumentKernelsMetadata ();
362+ }
363+
364+ void ThreadSanitizerOnSpirv::instrumentGlobalVariables () {
365+ SmallVector<Constant *, 8 > DeviceGlobalMetadata;
366+
367+ // Device global metadata is described by a structure
368+ // size_t device_global_size
369+ // size_t beginning address of the device global
370+ StructType *StructTy = StructType::get (IntptrTy, IntptrTy);
371+
372+ for (auto &G : M.globals ()) {
373+ if (isUnsupportedDeviceGlobal (G)) {
374+ for (auto *User : G.users ())
375+ if (auto *Inst = dyn_cast<Instruction>(User))
376+ Inst->setNoSanitizeMetadata ();
377+ continue ;
378+ }
379+
380+ DeviceGlobalMetadata.push_back (ConstantStruct::get (
381+ StructTy,
382+ ConstantInt::get (IntptrTy, DL.getTypeAllocSize (G.getValueType ())),
383+ ConstantExpr::getPointerCast (&G, IntptrTy)));
384+ }
385+
386+ if (DeviceGlobalMetadata.empty ())
387+ return ;
388+
389+ // Create meta data global to record device globals' information
390+ ArrayType *ArrayTy = ArrayType::get (StructTy, DeviceGlobalMetadata.size ());
391+ Constant *MetadataInitializer =
392+ ConstantArray::get (ArrayTy, DeviceGlobalMetadata);
393+ GlobalVariable *MsanDeviceGlobalMetadata = new GlobalVariable (
394+ M, MetadataInitializer->getType (), false , GlobalValue::AppendingLinkage,
395+ MetadataInitializer, " __TsanDeviceGlobalMetadata" , nullptr ,
396+ GlobalValue::NotThreadLocal, 1 );
397+ MsanDeviceGlobalMetadata->setUnnamedAddr (GlobalValue::UnnamedAddr::Local);
398+ }
399+
330400void ThreadSanitizerOnSpirv::instrumentKernelsMetadata () {
331401 SmallVector<Constant *, 8 > SpirKernelsMetadata;
332402
0 commit comments