diff --git a/.gitignore b/.gitignore index cb6cee5c002120..9c7406220878d4 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ # External projects /cheetah +/cilktools #==============================================================================# # Explicit files to ignore (only matches one). diff --git a/kitsune/cmake/caches/kitsune-dev.cmake b/kitsune/cmake/caches/kitsune-dev.cmake index 86fa1ab800b89b..15eb9d531f9363 100644 --- a/kitsune/cmake/caches/kitsune-dev.cmake +++ b/kitsune/cmake/caches/kitsune-dev.cmake @@ -32,7 +32,7 @@ set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "") # you are working on. By default we provide the full suite of # clang+tools, openmp, lld, and a debugger via lldb. set(LLVM_ENABLE_PROJECTS - clang;openmp; + clang;openmp CACHE STRING "") message(DEBUG " --> KITSUNE-DEV - enabled LLVM projects: ${LLVM_ENABLE_PROJECTS}") @@ -63,7 +63,7 @@ set(CLANG_CONFIG_FILE_USER_DIR "$ENV{HOME}/.kitsune" CACHE STRING "") set(CUDA_HOST_COMPILER "/usr/bin/gcc-8" CACHE STRING "") #endif() -set(_runtimes_list "cheetah") +set(_runtimes_list "cheetah;cilktools") # Various helpful LLVM-level settings for development/debugging. set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "") # sometimes errors get lost in all the warnings... diff --git a/kitsune/examples/kokkos/CMakeLists.txt b/kitsune/examples/kokkos/CMakeLists.txt index e85af41e4b7561..3fd8342b744ad4 100644 --- a/kitsune/examples/kokkos/CMakeLists.txt +++ b/kitsune/examples/kokkos/CMakeLists.txt @@ -57,7 +57,6 @@ set(_example_srcs set(_example_view_srcs raytrace.cpp - vecadd-views.cpp ) # Build the pure-kokkos serial target version of all the examples first. diff --git a/llvm/include/llvm/Analysis/MemoryBuiltins.h b/llvm/include/llvm/Analysis/MemoryBuiltins.h index 21c475a7aa65b7..7b1a5d9f7e999f 100644 --- a/llvm/include/llvm/Analysis/MemoryBuiltins.h +++ b/llvm/include/llvm/Analysis/MemoryBuiltins.h @@ -170,10 +170,13 @@ inline CallInst *extractCallocCall(Value *I, const TargetLibraryInfo *TLI) { bool isLibFreeFunction(const Function *F, const LibFunc TLIFn); /// isFreeCall - Returns non-null if the value is a call to the builtin free() -const CallInst *isFreeCall(const Value *I, const TargetLibraryInfo *TLI); +const CallInst *isFreeCall(const Value *I, const TargetLibraryInfo *TLI, + bool IgnoreBuiltinAttr = false); -inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI) { - return const_cast(isFreeCall((const Value*)I, TLI)); +inline CallInst *isFreeCall(Value *I, const TargetLibraryInfo *TLI, + bool IgnoreBuiltinAttr = false) { + return const_cast( + isFreeCall((const Value *)I, TLI, IgnoreBuiltinAttr)); } //===----------------------------------------------------------------------===// diff --git a/llvm/include/llvm/Transforms/Instrumentation/CSI.h b/llvm/include/llvm/Transforms/Instrumentation/CSI.h index 9117cbbbed2936..77fb766dcce3c4 100644 --- a/llvm/include/llvm/Transforms/Instrumentation/CSI.h +++ b/llvm/include/llvm/Transforms/Instrumentation/CSI.h @@ -71,7 +71,7 @@ static const char *const CsiDisableInstrumentationName = using csi_id_t = int64_t; static const csi_id_t CsiUnknownId = -1; static const csi_id_t CsiCallsiteUnknownTargetId = CsiUnknownId; -// See llvm/tools/clang/lib/CodeGen/CodeGenModule.h: +// See clang/lib/CodeGen/CodeGenModule.h: static const int CsiUnitCtorPriority = 0; /// Maintains a mapping from CSI ID to static data for that ID. @@ -803,6 +803,7 @@ class CsiLoadStoreProperty : public CsiProperty { IntegerType::get(C, PropBits.IsConstant), IntegerType::get(C, PropBits.IsOnStack), IntegerType::get(C, PropBits.MayBeCaptured), + IntegerType::get(C, PropBits.IsAtomic), IntegerType::get(C, PropBits.LoadReadBeforeWriteInBB), IntegerType::get(C, PropBits.Padding))); } @@ -844,6 +845,8 @@ class CsiLoadStoreProperty : public CsiProperty { void setIsOnStack(bool v) { PropValue.Fields.IsOnStack = v; } /// Set the value of the MayBeCaptured property. void setMayBeCaptured(bool v) { PropValue.Fields.MayBeCaptured = v; } + /// Set the value of the IsAtomic property. + void setIsAtomic(bool v) { PropValue.Fields.IsAtomic = v; } /// Set the value of the LoadReadBeforeWriteInBB property. void setLoadReadBeforeWriteInBB(bool v) { PropValue.Fields.LoadReadBeforeWriteInBB = v; @@ -858,8 +861,9 @@ class CsiLoadStoreProperty : public CsiProperty { unsigned IsConstant : 1; unsigned IsOnStack : 1; unsigned MayBeCaptured : 1; + unsigned IsAtomic : 1; unsigned LoadReadBeforeWriteInBB : 1; - uint64_t Padding : 53; + uint64_t Padding : 50; } Fields; uint64_t Bits; } Property; @@ -873,13 +877,14 @@ class CsiLoadStoreProperty : public CsiProperty { int IsConstant; int IsOnStack; int MayBeCaptured; + int IsAtomic; int LoadReadBeforeWriteInBB; int Padding; } PropertyBits; /// The number of bits representing each property. static constexpr PropertyBits PropBits = { - 8, 1, 1, 1, 1, 1, (64 - 8 - 1 - 1 - 1 - 1 - 1)}; + 8, 1, 1, 1, 1, 1, 1, (64 - 8 - 1 - 1 - 1 - 1 - 1 - 1)}; }; class CsiAllocaProperty : public CsiProperty { @@ -1049,18 +1054,6 @@ struct CSIImpl { Options(Options) { loadConfiguration(); } - CSIImpl(Module &M, CallGraph *CG, - function_ref GetDomTree, - function_ref GetLoopInfo, - function_ref GetTaskInfo, - function_ref GetTLI, - function_ref GetSE, - const CSIOptions &Options = CSIOptions()) - : M(M), DL(M.getDataLayout()), CG(CG), GetDomTree(GetDomTree), - GetLoopInfo(GetLoopInfo), GetTaskInfo(GetTaskInfo), GetTLI(GetTLI), - GetScalarEvolution(GetSE), Options(Options) { - loadConfiguration(); - } virtual ~CSIImpl() {} @@ -1073,7 +1066,7 @@ struct CSIImpl { static bool isVtableAccess(Instruction *I); static bool addrPointsToConstantData(Value *Addr); static bool isAtomic(Instruction *I); - static void getAllocFnArgs(const Instruction *I, + static bool getAllocFnArgs(const Instruction *I, SmallVectorImpl &AllocFnArgs, Type *SizeTy, Type *AddrTy, const TargetLibraryInfo &TLI); @@ -1095,6 +1088,9 @@ struct CSIImpl { static bool spawnsTapirLoopBody(DetachInst *DI, LoopInfo &LI, TaskInfo &TI); + static BasicBlock::iterator + getFirstInsertionPtInDetachedBlock(BasicBlock *Detached); + protected: /// Initialize the CSI pass. void initializeCsi(); @@ -1239,6 +1235,9 @@ struct CSIImpl { ZnwmSt11align_val_tRKSt9nothrow_t, ZnajSt11align_val_tRKSt9nothrow_t, ZnamSt11align_val_tRKSt9nothrow_t, + posix_memalign, + strdup, + strndup, LAST_ALLOCFNTY }; @@ -1250,8 +1249,8 @@ struct CSIImpl { return AllocFnTy::malloc; case LibFunc_valloc: return AllocFnTy::valloc; - // aligned_alloc(align_val_t, size_t) case LibFunc_aligned_alloc: + // aligned_alloc(align_val_t, size_t) return AllocFnTy::aligned_alloc; case LibFunc_calloc: return AllocFnTy::calloc; @@ -1331,6 +1330,15 @@ struct CSIImpl { case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: // new[](unsigned long, align_val_t, nothrow) return AllocFnTy::ZnamSt11align_val_tRKSt9nothrow_t; + case LibFunc_posix_memalign: + // posix_memalign(void **, size_t, size_t) + return AllocFnTy::posix_memalign; + case LibFunc_strdup: + // strdup(const char *) + return AllocFnTy::strdup; + case LibFunc_strndup: + // strdup(const char *, size_t) + return AllocFnTy::strndup; } } @@ -1496,6 +1504,7 @@ struct CSIImpl { DenseMap, SmallVector> ArgPHIs; + SmallPtrSet SyncsWithUnwinds; DenseMap callsAfterSync; std::unique_ptr Config; diff --git a/llvm/include/llvm/Transforms/Utils/TapirUtils.h b/llvm/include/llvm/Transforms/Utils/TapirUtils.h index 4b62ff7c42da35..88633c240cd8b3 100644 --- a/llvm/include/llvm/Transforms/Utils/TapirUtils.h +++ b/llvm/include/llvm/Transforms/Utils/TapirUtils.h @@ -43,6 +43,10 @@ bool isDetachedRethrow(const Instruction *I, const Value *SyncRegion = nullptr); /// taskframe.resume uses \p TaskFrame. bool isTaskFrameResume(const Instruction *I, const Value *TaskFrame = nullptr); +/// Returns true if the given basic block \p B is a placeholder successor of a +/// taskframe.resume or detached.rethrow. +bool isTapirPlaceholderSuccessor(const BasicBlock *B); + /// Returns a taskframe.resume that uses the given taskframe, or nullptr if no /// taskframe.resume uses this taskframe. InvokeInst *getTaskFrameResume(Value *TaskFrame); @@ -61,9 +65,10 @@ bool isSyncUnwind(const Instruction *I, const Value *SyncRegion = nullptr); /// instructions. bool isPlaceholderSuccessor(const BasicBlock *B); -/// Returns true if the given basic block ends a taskframe, false otherwise. If -/// \p TaskFrame is specified, then additionally checks that the -/// taskframe.end uses \p TaskFrame. +/// Returns true if the given basic block ends a taskframe, false otherwise. In +/// particular, this method checks if the penultimate instruction in the basic +/// block is a taskframe.end intrinsic call. If \p TaskFrame is specified, then +/// additionally checks that the taskframe.end uses \p TaskFrame. bool endsTaskFrame(const BasicBlock *B, const Value *TaskFrame = nullptr); /// Returns the spindle containing the taskframe.create used by task \p T, or @@ -218,7 +223,6 @@ class TapirLoopHints { enum SpawningStrategy { ST_SEQ, ST_DAC, - ST_OCL, ST_END, }; @@ -260,12 +264,9 @@ class TapirLoopHints { return "Spawn iterations sequentially"; case TapirLoopHints::ST_DAC: return "Use divide-and-conquer"; - case TapirLoopHints::ST_OCL: - return "Use opencl"; case TapirLoopHints::ST_END: return "Unknown"; } - return "Unknown"; } TapirLoopHints(const Loop *L) @@ -310,7 +311,7 @@ class TapirLoopHints { } void setAlreadyStripMined() { - //Grainsize.Value = 1; + Grainsize.Value = 1; Hint Hints[] = {Grainsize}; writeHintsToMetadata(Hints); } diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp index ed9d5a6df943dd..fd8c020b9be31c 100644 --- a/llvm/lib/Analysis/MemoryBuiltins.cpp +++ b/llvm/lib/Analysis/MemoryBuiltins.cpp @@ -465,11 +465,12 @@ bool llvm::isLibFreeFunction(const Function *F, const LibFunc TLIFn) { } /// isFreeCall - Returns non-null if the value is a call to the builtin free() -const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI) { +const CallInst *llvm::isFreeCall(const Value *I, const TargetLibraryInfo *TLI, + bool IgnoreBuiltinAttr) { bool IsNoBuiltinCall; const Function *Callee = getCalledFunction(I, /*LookThroughBitCast=*/false, IsNoBuiltinCall); - if (Callee == nullptr || IsNoBuiltinCall) + if (Callee == nullptr || (IsNoBuiltinCall && !IgnoreBuiltinAttr)) return nullptr; StringRef FnName = Callee->getName(); diff --git a/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp index 118b137c08812c..83f2d4559e4894 100644 --- a/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp @@ -112,7 +112,7 @@ static cl::opt cl::Hidden, cl::desc("Maximum number of uses to explore for a capture query.")); -static cl::opt MAAPChecks("cilksan-maap-checks", cl::init(false), +static cl::opt MAAPChecks("cilksan-maap-checks", cl::init(true), cl::Hidden, cl::desc("Enable or disable MAAP checks.")); @@ -126,12 +126,14 @@ static cl::opt cl::desc("Ignore the 'sanitize_cilk' attribute when choosing what to " "instrument.")); -static cl::opt InstrumentationSet( - "cilksan-instrumentation-set", cl::init(3), cl::Hidden, - cl::desc("Specify the set of instrumentation hooks to insert.")); static const unsigned SERIESPARALLEL = 0x1; static const unsigned SHADOWMEMORY = 0x2; +static cl::opt InstrumentationSet( + "cilksan-instrumentation-set", cl::init(SERIESPARALLEL | SHADOWMEMORY), + cl::Hidden, + cl::desc("Specify the set of instrumentation hooks to insert.")); +static const char *const CsanRtUnitInitName = "__csanrt_unit_init"; static const char *const CsiUnitObjTableName = "__csi_unit_obj_table"; static const char *const CsiUnitObjTableArrayName = "__csi_unit_obj_tables"; @@ -242,6 +244,7 @@ struct CilkSanitizerImpl : public CSIImpl { DenseMap &SRCounters, const DataLayout &DL); bool InstrumentLoops(SmallPtrSetImpl &LoopInstToHoist, SmallPtrSetImpl &LoopInstToSink, + SmallPtrSetImpl &TapirLoops, ScalarEvolution *); bool PerformDelayedInstrumentation(); @@ -334,13 +337,16 @@ struct CilkSanitizerImpl : public CSIImpl { static Constant *objTableToUnitObjTable(Module &M, StructType *UnitObjTableType, ObjectTable &ObjTable); + static bool isAllocFn(const Instruction *I, const TargetLibraryInfo *TLI); + static bool isLibCall(const Instruction &I, const TargetLibraryInfo *TLI); static bool simpleCallCannotRace(const Instruction &I); static bool shouldIgnoreCall(const Instruction &I); - static void getAllocFnArgs( + static bool getAllocFnArgs( const Instruction *I, SmallVectorImpl &AllocFnArgs, Type *SizeTy, Type *AddrTy, const TargetLibraryInfo &TLI); - void setupBlocks(Function &F, DominatorTree *DT = nullptr); + void setupBlocks(Function &F, DominatorTree *DT = nullptr, + LoopInfo *LI = nullptr); bool setupFunction(Function &F); // Methods for handling FED tables @@ -378,9 +384,14 @@ struct CilkSanitizerImpl : public CSIImpl { IRBuilder<> IRB(I); return instrumentAtomic(I, IRB); } + bool instrumentIntrinsicCall(Instruction *I, + SmallVectorImpl *MAAPVals = nullptr); + bool instrumentLibCall(Instruction *I, + SmallVectorImpl *MAAPVals = nullptr); bool instrumentCallsite(Instruction *I, SmallVectorImpl *MAAPVals = nullptr); bool suppressCallsite(Instruction *I); + bool instrumentAllocFnLibCall(Instruction *I, const TargetLibraryInfo *TLI); bool instrumentAllocationFn(Instruction *I, DominatorTree *DT, const TargetLibraryInfo *TLI); bool instrumentFree(Instruction *I, const TargetLibraryInfo *TLI); @@ -494,6 +505,9 @@ struct CilkSanitizerImpl : public CSIImpl { using MayBeCapturedMapTy = DenseMap; mutable MayBeCapturedMapTy MayBeCapturedCache; bool lookupPointerMayBeCaptured(const Value *Ptr) const { + if (!Ptr->getType()->isPointerTy()) + return false; + if (!MayBeCapturedCache.count(Ptr)) { if (isa(Ptr)) MayBeCapturedCache.lookup(Ptr); @@ -503,6 +517,9 @@ struct CilkSanitizerImpl : public CSIImpl { } return MayBeCapturedCache[Ptr]; } + + FunctionCallee getOrInsertSynthesizedHook(StringRef Name, FunctionType *T, + AttributeList AL); }; /// CilkSanitizer: instrument the code in module to find races. @@ -774,15 +791,16 @@ CallInst *CilkSanitizerImpl::createRTUnitInitCall(IRBuilder<> &IRB) { StructType *UnitObjTableType = getUnitObjTableType(C, ObjectTable::getPointerType(C)); - // Lookup __csirt_unit_init + // Lookup __csanrt_unit_init SmallVector InitArgTypes({IRB.getInt8PtrTy(), PointerType::get(UnitFedTableType, 0), PointerType::get(UnitObjTableType, 0), InitCallsiteToFunction->getType()}); FunctionType *InitFunctionTy = FunctionType::get(IRB.getVoidTy(), InitArgTypes, false); - RTUnitInit = M.getOrInsertFunction(CsiRtUnitInitName, InitFunctionTy); - assert(RTUnitInit); + RTUnitInit = M.getOrInsertFunction(CsanRtUnitInitName, InitFunctionTy); + assert(isa(RTUnitInit.getCallee()) && + "Failed to get or insert __csanrt_unit_init function"); ArrayType *UnitFedTableArrayType = ArrayType::get(UnitFedTableType, UnitFedTables.size()); @@ -801,7 +819,7 @@ CallInst *CilkSanitizerImpl::createRTUnitInitCall(IRBuilder<> &IRB) { Constant *Zero = ConstantInt::get(IRB.getInt32Ty(), 0); Value *GepArgs[] = {Zero, Zero}; - // Insert call to __csirt_unit_init + // Insert call to __csanrt_unit_init return IRB.CreateCall( RTUnitInit, {IRB.CreateGlobalStringPtr(M.getName()), @@ -830,10 +848,13 @@ void CilkSanitizerImpl::initializeCsanHooks() { Type *LargeNumBytesType = IntptrTy; Type *IDType = IRB.getInt64Ty(); + AttributeList GeneralFnAttrs; + GeneralFnAttrs = GeneralFnAttrs.addAttribute( + C, AttributeList::FunctionIndex, Attribute::InaccessibleMemOrArgMemOnly); + GeneralFnAttrs = GeneralFnAttrs.addAttribute(C, AttributeList::FunctionIndex, + Attribute::NoUnwind); { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); FnAttrs = FnAttrs.addParamAttribute(C, 2, Attribute::NoCapture); @@ -845,9 +866,7 @@ void CilkSanitizerImpl::initializeCsanHooks() { FuncPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanFuncExit = M.getOrInsertFunction("__csan_func_exit", FnAttrs, RetType, /* func_exit_id */ IDType, /* func_id */ IDType, @@ -855,27 +874,21 @@ void CilkSanitizerImpl::initializeCsanHooks() { } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); CsanRead = M.getOrInsertFunction("__csan_load", FnAttrs, RetType, IDType, AddrType, NumBytesType, LoadPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); CsanWrite = M.getOrInsertFunction("__csan_store", FnAttrs, RetType, IDType, AddrType, NumBytesType, StorePropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); CsanLargeRead = M.getOrInsertFunction("__csan_large_load", FnAttrs, RetType, @@ -883,9 +896,7 @@ void CilkSanitizerImpl::initializeCsanHooks() { LoadPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); CsanLargeWrite = M.getOrInsertFunction("__csan_large_store", FnAttrs, @@ -894,35 +905,27 @@ void CilkSanitizerImpl::initializeCsanHooks() { } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanBeforeCallsite = M.getOrInsertFunction("__csan_before_call", FnAttrs, IRB.getVoidTy(), IDType, /*callee func_id*/ IDType, IRB.getInt8Ty(), CallPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanAfterCallsite = M.getOrInsertFunction("__csan_after_call", FnAttrs, IRB.getVoidTy(), IDType, IDType, IRB.getInt8Ty(), CallPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanDetach = M.getOrInsertFunction("__csan_detach", FnAttrs, RetType, /* detach_id */ IDType, /* sync_reg */ IRB.getInt8Ty()); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 2, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 2, Attribute::ReadNone); FnAttrs = FnAttrs.addParamAttribute(C, 3, Attribute::NoCapture); @@ -935,9 +938,7 @@ void CilkSanitizerImpl::initializeCsanHooks() { TaskPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanTaskExit = M.getOrInsertFunction("__csan_task_exit", FnAttrs, RetType, /* task_exit_id */ IDType, /* task_id */ IDType, @@ -946,26 +947,20 @@ void CilkSanitizerImpl::initializeCsanHooks() { TaskExitPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanDetachContinue = M.getOrInsertFunction("__csan_detach_continue", FnAttrs, RetType, /* detach_continue_id */ IDType, /* detach_id */ IDType); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanSync = M.getOrInsertFunction("__csan_sync", FnAttrs, RetType, IDType, /* sync_reg */ IRB.getInt8Ty()); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); FnAttrs = FnAttrs.addParamAttribute(C, 5, Attribute::NoCapture); @@ -977,9 +972,7 @@ void CilkSanitizerImpl::initializeCsanHooks() { /* old ptr */ AddrType, /* property */ AllocFnPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::NoCapture); FnAttrs = FnAttrs.addParamAttribute(C, 1, Attribute::ReadNone); CsanAfterFree = M.getOrInsertFunction("__csan_after_free", FnAttrs, RetType, @@ -988,50 +981,38 @@ void CilkSanitizerImpl::initializeCsanHooks() { } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanDisableChecking = M.getOrInsertFunction("__cilksan_disable_checking", FnAttrs, RetType); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanEnableChecking = M.getOrInsertFunction("__cilksan_enable_checking", FnAttrs, RetType); } - Type *MAAPTy = IRB.getInt64Ty(); + Type *MAAPTy = IRB.getInt8Ty(); { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOrArgMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; FnAttrs = FnAttrs.addParamAttribute(C, 0, Attribute::NoCapture); GetMAAP = M.getOrInsertFunction("__csan_get_MAAP", FnAttrs, RetType, PointerType::get(MAAPTy, 0), IDType, IRB.getInt8Ty()); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; SetMAAP = M.getOrInsertFunction("__csan_set_MAAP", FnAttrs, RetType, MAAPTy, IDType); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanBeforeLoop = M.getOrInsertFunction( "__csan_before_loop", FnAttrs, IRB.getVoidTy(), IDType, IRB.getInt64Ty(), LoopPropertyTy); } { - AttributeList FnAttrs; - FnAttrs = FnAttrs.addAttribute(C, AttributeList::FunctionIndex, - Attribute::InaccessibleMemOnly); + AttributeList FnAttrs = GeneralFnAttrs; CsanAfterLoop = M.getOrInsertFunction("__csan_after_loop", FnAttrs, IRB.getVoidTy(), IDType, IRB.getInt8Ty(), LoopPropertyTy); @@ -1041,122 +1022,131 @@ void CilkSanitizerImpl::initializeCsanHooks() { Function *CsiAfterAllocaFn = cast(CsiAfterAlloca.getCallee()); CsiAfterAllocaFn->addParamAttr(1, Attribute::NoCapture); CsiAfterAllocaFn->addParamAttr(1, Attribute::ReadNone); - CsiAfterAllocaFn->addFnAttr(Attribute::InaccessibleMemOnly); + CsiAfterAllocaFn->addFnAttr(Attribute::InaccessibleMemOrArgMemOnly); + CsiAfterAllocaFn->setDoesNotThrow(); } static BasicBlock *SplitOffPreds( - BasicBlock *BB, SmallVectorImpl &Preds, DominatorTree *DT) { + BasicBlock *BB, SmallVectorImpl &Preds, DominatorTree *DT, + LoopInfo *LI) { if (BB->isLandingPad()) { SmallVector NewBBs; SplitLandingPadPredecessors(BB, Preds, ".csi-split-lp", ".csi-split", - NewBBs, DT); + NewBBs, DT, LI); return NewBBs[1]; } - SplitBlockPredecessors(BB, Preds, ".csi-split", DT); + SplitBlockPredecessors(BB, Preds, ".csi-split", DT, LI); return BB; } // Setup each block such that all of its predecessors belong to the same CSI ID // space. -static void setupBlock(BasicBlock *BB, DominatorTree *DT, +static void setupBlock(BasicBlock *BB, DominatorTree *DT, LoopInfo *LI, const TargetLibraryInfo *TLI) { if (BB->getUniquePredecessor()) return; SmallVector DetachPreds; - SmallVector DetRethrowPreds; SmallVector TFResumePreds; SmallVector SyncPreds; SmallVector SyncUnwindPreds; SmallVector AllocFnPreds; + DenseMap> LibCallPreds; SmallVector InvokePreds; bool HasOtherPredTypes = false; unsigned NumPredTypes = 0; // Partition the predecessors of the landing pad. for (BasicBlock *Pred : predecessors(BB)) { - if (isa(Pred->getTerminator())) + if (isa(Pred->getTerminator()) || + isa(Pred->getTerminator()) || + isDetachedRethrow(Pred->getTerminator())) DetachPreds.push_back(Pred); - else if (isDetachedRethrow(Pred->getTerminator())) - DetRethrowPreds.push_back(Pred); else if (isTaskFrameResume(Pred->getTerminator())) TFResumePreds.push_back(Pred); else if (isa(Pred->getTerminator())) SyncPreds.push_back(Pred); else if (isSyncUnwind(Pred->getTerminator())) SyncUnwindPreds.push_back(Pred); - else if (isAllocationFn(Pred->getTerminator(), TLI, false, true)) + else if (CilkSanitizerImpl::isAllocFn(Pred->getTerminator(), TLI)) AllocFnPreds.push_back(Pred); - else if (isa(Pred->getTerminator())) + else if (CilkSanitizerImpl::isLibCall(*Pred->getTerminator(), TLI)) { + const Function *Called = + dyn_cast(Pred->getTerminator())->getCalledFunction(); + LibCallPreds[Called].push_back(Pred); + } else if (isa(Pred->getTerminator())) InvokePreds.push_back(Pred); else HasOtherPredTypes = true; } NumPredTypes = static_cast(!DetachPreds.empty()) + - static_cast(!DetRethrowPreds.empty()) + static_cast(!TFResumePreds.empty()) + static_cast(!SyncPreds.empty()) + static_cast(!SyncUnwindPreds.empty()) + static_cast(!AllocFnPreds.empty()) + + static_cast(LibCallPreds.size()) + static_cast(!InvokePreds.empty()) + static_cast(HasOtherPredTypes); BasicBlock *BBToSplit = BB; // Split off the predecessors of each type. if (!SyncPreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, SyncPreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, SyncPreds, DT, LI); NumPredTypes--; } if (!SyncUnwindPreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, SyncUnwindPreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, SyncUnwindPreds, DT, LI); NumPredTypes--; } if (!AllocFnPreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, AllocFnPreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, AllocFnPreds, DT, LI); NumPredTypes--; } + if (!LibCallPreds.empty() && NumPredTypes > 1) { + for (auto KeyVal : LibCallPreds) { + if (NumPredTypes > 1) { + BBToSplit = SplitOffPreds(BBToSplit, KeyVal.second, DT, LI); + NumPredTypes--; + } + } + } if (!InvokePreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, InvokePreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, InvokePreds, DT, LI); NumPredTypes--; } if (!TFResumePreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, TFResumePreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, TFResumePreds, DT, LI); NumPredTypes--; } // We handle detach and detached.rethrow predecessors at the end to preserve // invariants on the CFG structure about the deadness of basic blocks after // detached-rethrows. if (!DetachPreds.empty() && NumPredTypes > 1) { - BBToSplit = SplitOffPreds(BBToSplit, DetachPreds, DT); + BBToSplit = SplitOffPreds(BBToSplit, DetachPreds, DT, LI); NumPredTypes--; } - // There is no need to split off detached-rethrow predecessors, since those - // successors of a detached-rethrow are dead up to where control flow merges - // with the unwind destination of a detach. - // if (!DetRethrowPreds.empty() && NumPredTypes > 1) { - // BBToSplit = SplitOffPreds(BBToSplit, DetRethrowPreds, DT); - // NumPredTypes--; - // } } // Setup all basic blocks such that each block's predecessors belong entirely to // one CSI ID space. -void CilkSanitizerImpl::setupBlocks(Function &F, DominatorTree *DT) { +void CilkSanitizerImpl::setupBlocks(Function &F, DominatorTree *DT, + LoopInfo *LI) { SmallPtrSet BlocksToSetup; for (BasicBlock &BB : F) { if (BB.isLandingPad()) BlocksToSetup.insert(&BB); - if (InvokeInst *II = dyn_cast(BB.getTerminator())) - BlocksToSetup.insert(II->getNormalDest()); - else if (SyncInst *SI = dyn_cast(BB.getTerminator())) + if (InvokeInst *II = dyn_cast(BB.getTerminator())) { + if (!isTapirPlaceholderSuccessor(II->getNormalDest())) + BlocksToSetup.insert(II->getNormalDest()); + } else if (SyncInst *SI = dyn_cast(BB.getTerminator())) BlocksToSetup.insert(SI->getSuccessor(0)); } for (BasicBlock *BB : BlocksToSetup) - setupBlock(BB, DT, &GetTLI(F)); + setupBlock(BB, DT, LI, &GetTLI(F)); } // Do not instrument known races/"benign races" that come from compiler @@ -1211,7 +1201,6 @@ bool CilkSanitizerImpl::LocalBaseObj(const Value *Addr, LoopInfo *LI, // If any base object is not an alloca or allocation function, then it's not // local. for (const Value *BaseObj : BaseObjs) { - // if (!isa(BaseObj) && !isAllocationFn(BaseObj, TLI)) { if (isa(BaseObj) || isNoAliasCall(BaseObj)) continue; @@ -1412,6 +1401,49 @@ void CilkSanitizerImpl::chooseInstructionsToInstrument( Local.clear(); } +bool CilkSanitizerImpl::isAllocFn(const Instruction *I, + const TargetLibraryInfo *TLI) { + if (!isa(I)) + return false; + + if (!TLI) + return false; + + if (isAllocationFn(I, TLI, /*LookThroughBitCast*/ false, + /*IgnoreBuiltinAttr*/ true)) + return true; + + if (const Function *Called = dyn_cast(I)->getCalledFunction()) { + if (Called->getName() != "posix_memalign") + return false; + + // Confirm that this function is a recognized library function + LibFunc F; + bool FoundLibFunc = TLI->getLibFunc(*Called, F); + return FoundLibFunc; + } + + return false; +} + +bool CilkSanitizerImpl::isLibCall(const Instruction &I, + const TargetLibraryInfo *TLI) { + if (!isa(I)) + return false; + + if (!TLI) + return false; + + if (const Function *Called = dyn_cast(&I)->getCalledFunction()) { + LibFunc F; + bool FoundLibFunc = TLI->getLibFunc(*Called, F); + if (FoundLibFunc) + return true; + } + + return false; +} + // Helper function to determine if the call-base instruction \p I should be // skipped when examining calls that affect race detection. Returns true if and // only if \p I is a simple call that cannot race. @@ -1489,7 +1521,7 @@ bool CilkSanitizerImpl::SimpleInstrumentor::InstrumentAnyMemIntrinsics( bool Result = false; for (Instruction *I : MemIntrinsics) { bool LocalResult = false; - if (auto *MT = dyn_cast(I)) { + if (isa(I)) { LocalResult |= CilkSanImpl.instrumentAnyMemIntrinAcc(I, /*Src*/ 1); LocalResult |= CilkSanImpl.instrumentAnyMemIntrinAcc(I, /*Dst*/ 0); } else { @@ -1512,11 +1544,18 @@ bool CilkSanitizerImpl::SimpleInstrumentor::InstrumentCalls( bool Result = false; for (Instruction *I : Calls) { // Allocation-function and free calls are handled separately. - if (isAllocationFn(I, TLI, false, true) || isFreeCall(I, TLI)) + if (isAllocFn(I, TLI) || isFreeCall(I, TLI, true)) continue; bool LocalResult = false; - LocalResult |= CilkSanImpl.instrumentCallsite(I, /*MAAPVals*/ nullptr); + if (isa(I)) + LocalResult |= + CilkSanImpl.instrumentIntrinsicCall(I, /*MAAPVals*/ nullptr); + else if (isLibCall(*I, TLI)) + LocalResult |= + CilkSanImpl.instrumentLibCall(I, /*MAAPVals*/ nullptr); + else + LocalResult |= CilkSanImpl.instrumentCallsite(I, /*MAAPVals*/ nullptr); if (LocalResult) { Result |= LocalResult; // Record the detaches for the task containing this instruction. These @@ -1646,7 +1685,7 @@ unsigned CilkSanitizerImpl::Instrumentor::RaceTypeToFlagVal( } static Value *getMAAPIRValue(IRBuilder<> &IRB, unsigned MV) { - return IRB.getInt64(MV); + return IRB.getInt8(MV); } // Insert per-argument MAAPs for this function @@ -1803,7 +1842,7 @@ bool CilkSanitizerImpl::Instrumentor::InstrumentCalls( bool Result = false; for (Instruction *I : Calls) { // Allocation-function and free calls are handled separately. - if (isAllocationFn(I, TLI, false, true) || isFreeCall(I, TLI)) + if (isAllocFn(I, TLI) || isFreeCall(I, TLI, true)) continue; bool LocalResult = false; @@ -1842,6 +1881,10 @@ bool CilkSanitizerImpl::Instrumentor::InstrumentCalls( // If this instruction cannot race, see if we can suppress it if (!RaceInfo::isRace(CallRT)) { + // Nothing to suppress if this is an intrinsic + if (isa(I)) + continue; + // We can only suppress calls whose functions don't have local races. if (!RaceInfo::isLocalRace(FuncRT)) { if (!CB->doesNotAccessMemory()) @@ -1910,7 +1953,12 @@ bool CilkSanitizerImpl::Instrumentor::InstrumentCalls( for (Value *MAAPVal : reverse(MAAPVals)) IRB.CreateCall(CilkSanImpl.SetMAAP, {MAAPVal, CalleeID}); - GetDetaches |= CilkSanImpl.instrumentCallsite(I, &MAAPVals); + if (isa(I)) + GetDetaches |= CilkSanImpl.instrumentIntrinsicCall(I, &MAAPVals); + else if (isLibCall(*I, TLI)) + GetDetaches |= CilkSanImpl.instrumentLibCall(I, &MAAPVals); + else + GetDetaches |= CilkSanImpl.instrumentCallsite(I, &MAAPVals); // If any instrumentation was inserted, collect associated instructions to // instrument. @@ -2512,6 +2560,9 @@ bool CilkSanitizerImpl::Instrumentor::InstrumentAncillaryInstructions( } } for (Instruction *I : AllocationFnCalls) { + // FIXME: This test won't identify posix_memalign calls as needing + // instrumentation, because posix_memalign modifies a pointer to the pointer + // to the object. if (CilkSanImpl.ObjectMRForRace.count(I) || CilkSanImpl.lookupPointerMayBeCaptured(I)) { CilkSanImpl.instrumentAllocationFn(I, DT, TLI); @@ -2624,7 +2675,8 @@ static Instruction *getLoopBlockInsertPt(BasicBlock *BB, FunctionCallee LoopHook // (which is unrelated to this), rename this to involve the word "hoist" or something. bool CilkSanitizerImpl::Instrumentor::InstrumentLoops( SmallPtrSetImpl &LoopInstToHoist, - SmallPtrSetImpl &LoopInstToSink, ScalarEvolution *SE) { + SmallPtrSetImpl &LoopInstToSink, + SmallPtrSetImpl &TapirLoops, ScalarEvolution *SE) { bool Result = false; // First insert computation for the hook arguments for all instructions to @@ -2664,7 +2716,8 @@ bool CilkSanitizerImpl::Instrumentor::InstrumentLoops( // Get the last address accessed. BasicBlock *Latch = L->getLoopLatch(); - const SCEV *BECount = SE->getExitCount(L, Latch); + const SCEV *BECount = TapirLoops.count(L) ? SE->getExitCount(L, Latch) + : SE->getBackedgeTakenCount(L); const SCEV *LastAddr = SrcAR->evaluateAtIteration(BECount, *SE); // Get the size (number of bytes) of the address range accessed. @@ -2965,18 +3018,22 @@ bool CilkSanitizerImpl::setupFunction(Function &F) { << " for instrumentation\n"); if (Options.CallsMayThrow) + // Promote calls to invokes to insert instrumentation in exception-handling + // code. setupCalls(F); - setupBlocks(F); - DominatorTree *DT = &GetDomTree(F); LoopInfo &LI = GetLoopInfo(F); if (Options.InstrumentLoops) + // Simplify loops to prepare for loop instrumentation for (Loop *L : LI) simplifyLoop(L, DT, &LI, nullptr, nullptr, nullptr, /* PreserveLCSSA */ false); + // Canonicalize the CFG for instrumentation + setupBlocks(F, DT, &LI); + return true; } @@ -3012,6 +3069,8 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { SmallVector LocalLoadsAndStores; SmallVector AtomicAccesses; SmallVector MemIntrinCalls; + SmallVector IntrinsicCalls; + SmallVector LibCalls; SmallVector Callsites; // Ancillary instructions SmallPtrSet Allocas; @@ -3024,6 +3083,7 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { // Find instructions that can be hoisted or sinked SmallPtrSet LoopInstToHoist; SmallPtrSet LoopInstToSink; + SmallPtrSet TapirLoops; const TargetLibraryInfo *TLI = &GetTLI(F); DominatorTree *DT = &GetDomTree(F); @@ -3033,7 +3093,6 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { ICFLoopSafetyInfo SafetyInfo(DT); - // ScalarEvolution &SE = (*GetScalarEvolution)(F); ScalarEvolution &SE = *(RI.getSE()); for (BasicBlock &BB : F) { @@ -3081,8 +3140,10 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { // SE.isKnownNonNegative(Diff) will be false. Diff = SE.getAddExpr(Size, Stride); } - const SCEV *TripCount = getRuntimeTripCount( - *L, &SE, static_cast(getTaskIfTapirLoop(L, &TI))); + bool isTapirLoop = static_cast(getTaskIfTapirLoop(L, &TI)); + if (isTapirLoop) + TapirLoops.insert(L); + const SCEV *TripCount = getRuntimeTripCount(*L, &SE, isTapirLoop); if (SE.isKnownNonNegative(Diff)) { if (!isa(TripCount) && @@ -3112,7 +3173,7 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { AtomicAccesses.push_back(&Inst); else if (isa(Inst)) Allocas.insert(&Inst); - else if (isa(Inst) || isa(Inst)) { + else if (isa(Inst)) { // if (CallInst *CI = dyn_cast(&Inst)) // maybeMarkSanitizerLibraryCallNoBuiltin(CI, TLI); @@ -3131,15 +3192,23 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { // Record this function call as either an allocation function, a call to // free (or delete), a memory intrinsic, or an ordinary real function // call. - if (isAllocationFn(&Inst, TLI, /*LookThroughBitCast*/ false, - /*IgnoreBuiltinAttr*/ true)) + if (isAllocFn(&Inst, TLI)) AllocationFnCalls.insert(&Inst); - else if (isFreeCall(&Inst, TLI)) + else if (isFreeCall(&Inst, TLI, /*IgnoreBuiltinAttr*/ true)) FreeCalls.insert(&Inst); else if (isa(Inst)) MemIntrinCalls.push_back(&Inst); - else if (!simpleCallCannotRace(Inst) && !shouldIgnoreCall(Inst)) - Callsites.push_back(&Inst); + else if (!simpleCallCannotRace(Inst) && !shouldIgnoreCall(Inst)) { + if (isa(&Inst)) { + if (Inst.mayReadOrWriteMemory()) + IntrinsicCalls.push_back(&Inst); + } else if (isLibCall(Inst, TLI)) { + if (Inst.mayReadOrWriteMemory()) + LibCalls.push_back(&Inst); + } else { + Callsites.push_back(&Inst); + } + } } // Add the current set of local loads and stores to be considered for @@ -3178,6 +3247,8 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { Result |= FuncI.InstrumentSimpleInstructions(AllLoadsAndStores); Result |= FuncI.InstrumentSimpleInstructions(AtomicAccesses); Result |= FuncI.InstrumentAnyMemIntrinsics(MemIntrinCalls); + Result |= FuncI.InstrumentCalls(IntrinsicCalls); + Result |= FuncI.InstrumentCalls(LibCalls); Result |= FuncI.InstrumentCalls(Callsites); // Instrument ancillary instructions including allocas, allocation-function @@ -3187,12 +3258,15 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { SRCounters, DL); } else { Instrumentor FuncI(*this, RI, TI, LI, DT, TLI); + // Insert MAAP flags for each function argument. FuncI.InsertArgMAAPs(F, FuncId); Result |= FuncI.InstrumentSimpleInstructions(AllLoadsAndStores); Result |= FuncI.InstrumentSimpleInstructions(AtomicAccesses); Result |= FuncI.InstrumentAnyMemIntrinsics(MemIntrinCalls); + Result |= FuncI.InstrumentCalls(IntrinsicCalls); + Result |= FuncI.InstrumentCalls(LibCalls); Result |= FuncI.InstrumentCalls(Callsites); // Find detaches that need to be instrumented for loop instructions whose @@ -3209,8 +3283,8 @@ bool CilkSanitizerImpl::instrumentFunctionUsingRI(Function &F) { // Hoist and sink instrumentation when possible (applies to all loops, // not just Tapir loops) // Also inserts MAAP checks for hoisted/sinked instrumentation - Result |= FuncI.InstrumentLoops(LoopInstToHoist, LoopInstToSink, &SE); - + Result |= + FuncI.InstrumentLoops(LoopInstToHoist, LoopInstToSink, TapirLoops, &SE); // Once we have handled ancillary instructions, we've done the necessary // analysis on this function. We now perform delayed instrumentation, which @@ -3334,6 +3408,7 @@ bool CilkSanitizerImpl::instrumentLoadOrStore(Instruction *I, : cast(I)->getAlignment(); CsiLoadStoreProperty Prop; Prop.setAlignment(Alignment); + Prop.setIsAtomic(I->isAtomic()); if (IsWrite) { // Instrument store uint64_t LocalId = StoreFED.add(*I); @@ -3388,6 +3463,7 @@ bool CilkSanitizerImpl::instrumentAtomic(Instruction *I, IRBuilder<> &IRB) { if (!(InstrumentationSet & SHADOWMEMORY)) return true; + Prop.setIsAtomic(true); uint64_t LocalId = StoreFED.add(*I); uint64_t StoreObjId = StoreObj.add(*I, lookupUnderlyingObject(Addr)); assert(LocalId == StoreObjId && @@ -3403,6 +3479,299 @@ bool CilkSanitizerImpl::instrumentAtomic(Instruction *I, IRBuilder<> &IRB) { return true; } +FunctionCallee CilkSanitizerImpl::getOrInsertSynthesizedHook(StringRef Name, + FunctionType *T, + AttributeList AL) { + // TODO: Modify this routine to insert a call to a default library hook for + // any call to a library function or intrinsic that the Cilksan runtime does + // not recognize. To do this, we may want to modify the CilkSanitizer pass + // accept a list of hooks recognized by the Cilksan runtime, e.g., in the form + // of a bitcode file. + return M.getOrInsertFunction(Name, T, AL); +} + +bool CilkSanitizerImpl::instrumentIntrinsicCall( + Instruction *I, SmallVectorImpl *MAAPVals) { + assert(!callsPlaceholderFunction(*I) && + "instrumentIntrinsicCall called on placeholder function"); + + // Only insert instrumentation if requested + if (!(InstrumentationSet & SERIESPARALLEL)) + return true; + + CallBase *CB = dyn_cast(I); + if (!CB) + return false; + Function *Called = CB->getCalledFunction(); + + IRBuilder<> IRB(I); + LLVMContext &Ctx = IRB.getContext(); + uint64_t LocalId = CallsiteFED.add(*I); + Value *CallsiteId = CallsiteFED.localToGlobalId(LocalId, IRB); + Value *FuncId = GetCalleeFuncID(Called, IRB); + assert(FuncId != NULL); + + Value *NumMVVal = IRB.getInt8(0); + if (MAAPVals && !MAAPVals->empty()) { + unsigned NumMV = MAAPVals->size(); + NumMVVal = IRB.getInt8(NumMV); + } + + CsiCallProperty Prop; + // TODO: Set appropriate property values for this intrinsic call + Value *PropVal = Prop.getValue(IRB); + + // Since C/C++ does not like '.' characters in function names, convert '.' to + // '_' in the hook name. + SmallString<256> Buf; + for (char C : Called->getName().bytes()) { + if ('.' == C) + Buf.push_back('_'); + else + Buf.push_back(C); + } + + Type *IDType = IRB.getInt64Ty(); + AttributeList FnAttrs; + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::InaccessibleMemOrArgMemOnly); + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::NoUnwind); + + // If the intrinsic does not return, insert the hook before the intrinsic. + if (CB->doesNotReturn()) { + // Synthesize the before hook for this function. + SmallVector BeforeHookParamTys( + {IDType, /*callee func_id*/ IDType, + /*Num MAAPVal*/ IRB.getInt8Ty(), CsiCallProperty::getType(Ctx)}); + SmallVector BeforeHookParamVals( + {CallsiteId, FuncId, NumMVVal, PropVal}); + + // Populate the BeforeHook parameters with the parameters of the + // instrumented function itself. + Value *SavedStack = nullptr; + const DataLayout &DL = M.getDataLayout(); + for (Value *Arg : CB->args()) { + if (!Arg->getType()->isVectorTy()) { + BeforeHookParamTys.push_back(Arg->getType()); + BeforeHookParamVals.push_back(Arg); + continue; + } + // We need to deal with a vector-type argument. Spill the vector onto the + // stack. + + // Save the stack pointer, if we haven't already + if (!SavedStack) + SavedStack = + IRB.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::stacksave)); + + // Spill the vector argument onto the stack + VectorType *VecTy = cast(Arg->getType()); + AllocaInst *ArgSpill = IRB.CreateAlloca(VecTy); + IRB.CreateAlignedStore(Arg, ArgSpill, DL.getStackAlignment()); + + // Add the spilled vector argument + BeforeHookParamTys.push_back(ArgSpill->getType()); + BeforeHookParamVals.push_back(ArgSpill); + } + FunctionType *BeforeHookTy = FunctionType::get( + IRB.getVoidTy(), BeforeHookParamTys, Called->isVarArg()); + FunctionCallee BeforeIntrinCallHook = getOrInsertSynthesizedHook( + ("__csan_" + Buf).str(), BeforeHookTy, FnAttrs); + + // Insert the hook before the call + insertHookCall(I, BeforeIntrinCallHook, BeforeHookParamVals); + + // If we previously saved the stack pointer, restore it + if (SavedStack) + IRB.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::stackrestore), + {SavedStack}); + return true; + } + + // Otherwise, insert the hook after the intrinsic. + assert(!isa(I) && + "instrumentIntrinsicCall called on invoke instruction"); + + BasicBlock::iterator Iter(I); + Iter++; + IRB.SetInsertPoint(&*Iter); + + // Synthesize the after hook for this function. + SmallVector AfterHookParamTys({IDType, /*callee func_id*/ IDType, + /*Num MAAPVal*/ IRB.getInt8Ty(), + CsiCallProperty::getType(Ctx)}); + SmallVector AfterHookParamVals( + {CallsiteId, FuncId, NumMVVal, PropVal}); + + // Populate the AfterHook parameters with the parameters of the instrumented + // function itself. + Value *SavedStack = nullptr; + const DataLayout &DL = M.getDataLayout(); + if (!Called->getReturnType()->isVoidTy()) { + if (!Called->getReturnType()->isVectorTy()) { + AfterHookParamTys.push_back(Called->getReturnType()); + AfterHookParamVals.push_back(CB); + } else { + // We need to deal with a vector-type return value. Spill the vector onto + // the stack. + + // Save the stack pointer, if we haven't already + if (!SavedStack) + SavedStack = + IRB.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::stacksave)); + + // Spill the vector return value onto the stack + VectorType *VecTy = cast(Called->getReturnType()); + AllocaInst *RetSpill = IRB.CreateAlloca(VecTy); + IRB.CreateAlignedStore(CB, RetSpill, DL.getStackAlignment()); + + // Add the spilled vector return value + AfterHookParamTys.push_back(RetSpill->getType()); + AfterHookParamVals.push_back(RetSpill); + } + } + for (Value *Arg : CB->args()) { + if (!Arg->getType()->isVectorTy()) { + AfterHookParamTys.push_back(Arg->getType()); + AfterHookParamVals.push_back(Arg); + continue; + } + // We need to deal with a vector-type argument. Spill the vector onto the + // stack. + + // Save the stack pointer, if we haven't already + if (!SavedStack) + SavedStack = + IRB.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::stacksave)); + + // Spill the vector argument onto the stack + VectorType *VecTy = cast(Arg->getType()); + AllocaInst *ArgSpill = IRB.CreateAlloca(VecTy); + IRB.CreateAlignedStore(Arg, ArgSpill, DL.getStackAlignment()); + + // Add the spolled vector argument + AfterHookParamTys.push_back(ArgSpill->getType()); + AfterHookParamVals.push_back(ArgSpill); + } + FunctionType *AfterHookTy = + FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); + FunctionCallee AfterIntrinCallHook = + getOrInsertSynthesizedHook(("__csan_" + Buf).str(), AfterHookTy, FnAttrs); + + // Insert the hook call + insertHookCall(&*Iter, AfterIntrinCallHook, AfterHookParamVals); + + if (SavedStack) { + IRB.CreateCall(Intrinsic::getDeclaration(&M, Intrinsic::stackrestore), + {SavedStack}); + } + return true; +} + +bool CilkSanitizerImpl::instrumentLibCall(Instruction *I, + SmallVectorImpl *MAAPVals) { + // Only insert instrumentation if requested + if (!(InstrumentationSet & SERIESPARALLEL)) + return true; + + bool IsInvoke = isa(I); + CallBase *CB = dyn_cast(I); + if (!CB) + return false; + Function *Called = CB->getCalledFunction(); + + IRBuilder<> IRB(I); + LLVMContext &Ctx = IRB.getContext(); + uint64_t LocalId = CallsiteFED.add(*I); + Value *DefaultID = getDefaultID(IRB); + Value *CallsiteId = CallsiteFED.localToGlobalId(LocalId, IRB); + Value *FuncId = GetCalleeFuncID(Called, IRB); + assert(FuncId != NULL); + + Value *NumMVVal = IRB.getInt8(0); + if (MAAPVals && !MAAPVals->empty()) { + unsigned NumMV = MAAPVals->size(); + NumMVVal = IRB.getInt8(NumMV); + } + + CsiCallProperty Prop; + Value *DefaultPropVal = Prop.getValue(IRB); + // TODO: Set appropriate property values for this intrinsic call + Value *PropVal = Prop.getValue(IRB); + + Type *IDType = IRB.getInt64Ty(); + AttributeList FnAttrs; + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::InaccessibleMemOrArgMemOnly); + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::NoUnwind); + + // If the intrinsic does not return, insert the hook before the intrinsic. + if (CB->doesNotReturn()) { + // Synthesize the before hook for this function. + SmallVector BeforeHookParamTys( + {IDType, /*callee func_id*/ IDType, + /*MAAP_count*/ IRB.getInt8Ty(), CsiCallProperty::getType(Ctx)}); + SmallVector BeforeHookParamVals( + {CallsiteId, FuncId, NumMVVal, PropVal}); + BeforeHookParamTys.append(Called->getFunctionType()->param_begin(), + Called->getFunctionType()->param_end()); + BeforeHookParamVals.append(CB->arg_begin(), CB->arg_end()); + FunctionType *BeforeHookTy = FunctionType::get( + IRB.getVoidTy(), BeforeHookParamTys, Called->isVarArg()); + FunctionCallee BeforeLibCallHook = getOrInsertSynthesizedHook( + ("__csan_" + Called->getName()).str(), BeforeHookTy, FnAttrs); + + insertHookCall(I, BeforeLibCallHook, BeforeHookParamVals); + return true; + } + + // Otherwise, insert the hook after the intrinsic. + + // Synthesize the after hook for this function. + SmallVector AfterHookParamTys( + {IDType, /*callee func_id*/ IDType, + /*Num MAAPVal*/ IRB.getInt8Ty(), CsiCallProperty::getType(Ctx)}); + SmallVector AfterHookParamVals( + {CallsiteId, FuncId, NumMVVal, PropVal}); + SmallVector AfterHookDefaultVals( + {DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal}); + if (!Called->getReturnType()->isVoidTy()) { + AfterHookParamTys.push_back(Called->getReturnType()); + AfterHookParamVals.push_back(CB); + AfterHookDefaultVals.push_back( + Constant::getNullValue(Called->getReturnType())); + } + AfterHookParamTys.append(Called->getFunctionType()->param_begin(), + Called->getFunctionType()->param_end()); + AfterHookParamVals.append(CB->arg_begin(), CB->arg_end()); + for (Value *Arg : CB->args()) + AfterHookDefaultVals.push_back(Constant::getNullValue(Arg->getType())); + FunctionType *AfterHookTy = + FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); + FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook( + ("__csan_" + Called->getName()).str(), AfterHookTy, FnAttrs); + + BasicBlock::iterator Iter(I); + if (IsInvoke) { + // There are two "after" positions for invokes: the normal block and the + // exception block. + InvokeInst *II = cast(I); + insertHookCallInSuccessorBB( + II->getNormalDest(), II->getParent(), AfterLibCallHook, + AfterHookParamVals, AfterHookDefaultVals); + // Don't insert any instrumentation in the exception block. + } else { + // Simple call instruction; there is only one "after" position. + Iter++; + IRB.SetInsertPoint(&*Iter); + insertHookCall(&*Iter, AfterLibCallHook, AfterHookParamVals); + } + + return true; +} + bool CilkSanitizerImpl::instrumentCallsite(Instruction *I, SmallVectorImpl *MAAPVals) { if (callsPlaceholderFunction(*I)) @@ -3588,8 +3957,6 @@ bool CilkSanitizerImpl::instrumentAnyMemIntrinAcc(Instruction *I, if (!(InstrumentationSet & SHADOWMEMORY)) return true; - // assert(IsMemIntrinDstOperand(OperandNum) && - // "Race on memset not on destination operand."); Value *Addr = M->getDest(); Prop.setAlignment(M->getDestAlignment()); uint64_t LocalId = StoreFED.add(*I); @@ -3676,6 +4043,7 @@ bool CilkSanitizerImpl::instrumentDetach(DetachInst *DI, unsigned SyncRegNum, // Find the detached block, continuation, and associated reattaches. BasicBlock *DetachedBlock = DI->getDetached(); BasicBlock *ContinueBlock = DI->getContinue(); + Task *T = TI.getTaskFor(DetachedBlock); SmallVector TaskExits, TaskResumes; SmallVector SharedEHExits; getTaskExits(DI, TaskExits, TaskResumes, SharedEHExits, TI); @@ -3683,7 +4051,7 @@ bool CilkSanitizerImpl::instrumentDetach(DetachInst *DI, unsigned SyncRegNum, // Instrument the entry and exit points of the detached task. { // Instrument the entry point of the detached task. - IRBuilder<> IRB(&*DetachedBlock->getFirstInsertionPt()); + IRBuilder<> IRB(&*getFirstInsertionPtInDetachedBlock(DetachedBlock)); uint64_t LocalID = TaskFED.add(*DetachedBlock); Value *TaskID = TaskFED.localToGlobalId(LocalID, IDBuilder); CsiTaskProperty Prop; @@ -3698,8 +4066,6 @@ bool CilkSanitizerImpl::instrumentDetach(DetachInst *DI, unsigned SyncRegNum, Instruction *Call = IRB.CreateCall(CsanTaskEntry, {TaskID, DetachID, FrameAddr, StackSave, Prop.getValue(IRB)}); - // Instruction *Call = IRB.CreateCall(CsanTaskEntry, - // {TaskID, DetachID, FrameAddr}); IRB.SetInstDebugLocation(Call); // Instrument the exit points of the detached tasks. @@ -3729,7 +4095,6 @@ bool CilkSanitizerImpl::instrumentDetach(DetachInst *DI, unsigned SyncRegNum, NumInstrumentedDetachExits++; } - Task *T = TI.getTaskFor(DetachedBlock); Value *DefaultID = getDefaultID(IDBuilder); for (Spindle *SharedEH : SharedEHExits) { CsiTaskExitProperty ExitProp; @@ -3760,12 +4125,27 @@ bool CilkSanitizerImpl::instrumentDetach(DetachInst *DI, unsigned SyncRegNum, // Instrument the unwind of the detach, if it exists. if (DI->hasUnwindDest()) { BasicBlock *UnwindBlock = DI->getUnwindDest(); + BasicBlock *PredBlock = DI->getParent(); + if (Value *TF = T->getTaskFrameUsed()) { + // If the detached task uses a taskframe, then we want to insert the + // detach_continue instrumentation for the unwind destination after the + // taskframe.resume. + UnwindBlock = getTaskFrameResumeDest(TF); + assert(UnwindBlock && + "Detach with unwind uses a taskframe with no resume"); + PredBlock = getTaskFrameResume(TF)->getParent(); + } Value *DefaultID = getDefaultID(IDBuilder); uint64_t LocalID = DetachContinueFED.add(*UnwindBlock); Value *ContinueID = DetachContinueFED.localToGlobalId(LocalID, IDBuilder); - insertHookCallInSuccessorBB(UnwindBlock, DI->getParent(), + insertHookCallInSuccessorBB(UnwindBlock, PredBlock, CsanDetachContinue, {ContinueID, DetachID}, {DefaultID, DefaultID}); + for (BasicBlock *DRPred : predecessors(UnwindBlock)) + if (isDetachedRethrow(DRPred->getTerminator(), DI->getSyncRegion())) + insertHookCallInSuccessorBB(UnwindBlock, DRPred, CsanDetachContinue, + {ContinueID, DetachID}, + {DefaultID, DefaultID}); } return true; } @@ -3912,7 +4292,7 @@ bool CilkSanitizerImpl::instrumentAlloca(Instruction *I) { return true; } -static Value *getHeapObject(Instruction *I) { +static Value *getHeapObject(Value *I) { Value *Object = nullptr; unsigned NumOfBitCastUses = 0; @@ -3938,22 +4318,18 @@ static Value *getHeapObject(Instruction *I) { return I; } -void CilkSanitizerImpl::getAllocFnArgs( +bool CilkSanitizerImpl::getAllocFnArgs( const Instruction *I, SmallVectorImpl &AllocFnArgs, Type *SizeTy, Type *AddrTy, const TargetLibraryInfo &TLI) { - const Function *Called = nullptr; - if (const CallInst *CI = dyn_cast(I)) - Called = CI->getCalledFunction(); - else if (const InvokeInst *II = dyn_cast(I)) - Called = II->getCalledFunction(); + const Function *Called = dyn_cast(I)->getCalledFunction();; LibFunc F; bool FoundLibFunc = TLI.getLibFunc(*Called, F); if (!FoundLibFunc) - return; + return false; switch(F) { - default: return; + default: return false; // TODO: Add aligned new's to this list after they're added to TLI. case LibFunc_malloc: case LibFunc_valloc: @@ -3986,8 +4362,36 @@ void CilkSanitizerImpl::getAllocFnArgs( AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; + } + case LibFunc_ZnwjSt11align_val_t: + case LibFunc_ZnwmSt11align_val_t: + case LibFunc_ZnajSt11align_val_t: + case LibFunc_ZnamSt11align_val_t: + case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t: + case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: + case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t: + case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: { + if (const CallInst *CI = dyn_cast(I)) { + AllocFnArgs.push_back(CI->getArgOperand(0)); + // Number of elements = 1 + AllocFnArgs.push_back(ConstantInt::get(SizeTy, 1)); + // Alignment + AllocFnArgs.push_back(CI->getArgOperand(1)); + // Old pointer = NULL + AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); + } else { + const InvokeInst *II = cast(I); + AllocFnArgs.push_back(II->getArgOperand(0)); + // Number of elements = 1 + AllocFnArgs.push_back(ConstantInt::get(SizeTy, 1)); + // Alignment + AllocFnArgs.push_back(II->getArgOperand(1)); + // Old pointer = NULL + AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); } + return true; + } case LibFunc_calloc: { const CallInst *CI = cast(I); @@ -3999,7 +4403,7 @@ void CilkSanitizerImpl::getAllocFnArgs( AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; } case LibFunc_realloc: case LibFunc_reallocf: @@ -4013,7 +4417,7 @@ void CilkSanitizerImpl::getAllocFnArgs( AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer AllocFnArgs.push_back(CI->getArgOperand(0)); - return; + return true; } case LibFunc_aligned_alloc: { @@ -4026,43 +4430,135 @@ void CilkSanitizerImpl::getAllocFnArgs( AllocFnArgs.push_back(CI->getArgOperand(0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; } } } -bool CilkSanitizerImpl::instrumentAllocationFn(Instruction *I, - DominatorTree *DT, - const TargetLibraryInfo *TLI) { +bool CilkSanitizerImpl::instrumentAllocFnLibCall(Instruction *I, + const TargetLibraryInfo *TLI) { // Only insert instrumentation if requested if (!(InstrumentationSet & SHADOWMEMORY)) return true; bool IsInvoke = isa(I); - Function *Called = nullptr; - if (CallInst *CI = dyn_cast(I)) - Called = CI->getCalledFunction(); - else if (InvokeInst *II = dyn_cast(I)) - Called = II->getCalledFunction(); - - assert(Called && "Could not get called function for allocation fn."); + CallBase *CB = dyn_cast(I); + if (!CB) + return false; + Function *Called = CB->getCalledFunction(); + // Get the CSI IDs for this hook IRBuilder<> IRB(I); + LLVMContext &Ctx = IRB.getContext(); Value *DefaultID = getDefaultID(IRB); uint64_t LocalId = AllocFnFED.add(*I); Value *AllocFnId = AllocFnFED.localToGlobalId(LocalId, IRB); - uint64_t AllocFnObjId = AllocFnObj.add(*I, getHeapObject(I)); + Value *FuncId = GetCalleeFuncID(Called, IRB); + assert(FuncId != NULL); + + // Get the ID for the corresponding heap object + Value *HeapObj = nullptr; + if ("posix_memalign" == Called->getName()) + HeapObj = getHeapObject(CB->getArgOperand(0)); + else + HeapObj = getHeapObject(I); + uint64_t AllocFnObjId = AllocFnObj.add(*I, HeapObj); assert(LocalId == AllocFnObjId && "Allocation fn received different ID's in FED and object tables."); + // TODO: Propagate MAAPs to allocation-function library calls + Value *NumMVVal = IRB.getInt8(0); + + CsiAllocFnProperty Prop; + Value *DefaultPropVal = Prop.getValue(IRB); + LibFunc AllocLibF; + TLI->getLibFunc(*Called, AllocLibF); + Prop.setAllocFnTy(static_cast(getAllocFnTy(AllocLibF))); + Value *PropVal = Prop.getValue(IRB); + + Type *IDType = IRB.getInt64Ty(); + AttributeList FnAttrs; + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::InaccessibleMemOrArgMemOnly); + FnAttrs = FnAttrs.addAttribute(Ctx, AttributeList::FunctionIndex, + Attribute::NoUnwind); + + // Synthesize the after hook for this function. + SmallVector AfterHookParamTys({IDType, /*callee func_id*/ IDType, + /*MAAP_count*/ IRB.getInt8Ty(), + CsiAllocFnProperty::getType(Ctx)}); + SmallVector AfterHookParamVals( + {AllocFnId, FuncId, NumMVVal, PropVal}); + SmallVector AfterHookDefaultVals( + {DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal}); + if (!Called->getReturnType()->isVoidTy()) { + AfterHookParamTys.push_back(Called->getReturnType()); + AfterHookParamVals.push_back(CB); + AfterHookDefaultVals.push_back( + Constant::getNullValue(Called->getReturnType())); + } + AfterHookParamTys.append(Called->getFunctionType()->param_begin(), + Called->getFunctionType()->param_end()); + AfterHookParamVals.append(CB->arg_begin(), CB->arg_end()); + for (Value *Arg : CB->args()) + AfterHookDefaultVals.push_back(Constant::getNullValue(Arg->getType())); + FunctionType *AfterHookTy = + FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); + FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook( + ("__csan_alloc_" + Called->getName()).str(), AfterHookTy, FnAttrs); + + // Insert the hook after the call. + BasicBlock::iterator Iter(I); + if (IsInvoke) { + // There are two "after" positions for invokes: the normal block and the + // exception block. + InvokeInst *II = cast(I); + insertHookCallInSuccessorBB( + II->getNormalDest(), II->getParent(), AfterLibCallHook, + AfterHookParamVals, AfterHookDefaultVals); + // Don't insert any instrumentation in the exception block. + } else { + // Simple call instruction; there is only one "after" position. + Iter++; + IRB.SetInsertPoint(&*Iter); + insertHookCall(&*Iter, AfterLibCallHook, AfterHookParamVals); + } + + NumInstrumentedAllocFns++; + return true; +} + +bool CilkSanitizerImpl::instrumentAllocationFn(Instruction *I, + DominatorTree *DT, + const TargetLibraryInfo *TLI) { + // Only insert instrumentation if requested + if (!(InstrumentationSet & SHADOWMEMORY)) + return true; + + bool IsInvoke = isa(I); + assert(isa(I) && + "instrumentAllocationFn not given a call or invoke instruction."); + Function *Called = dyn_cast(I)->getCalledFunction(); + assert(Called && "Could not get called function for allocation fn."); + + IRBuilder<> IRB(I); SmallVector AllocFnArgs; - getAllocFnArgs(I, AllocFnArgs, IntptrTy, IRB.getInt8PtrTy(), *TLI); + if (!getAllocFnArgs(I, AllocFnArgs, IntptrTy, IRB.getInt8PtrTy(), *TLI)) { + return instrumentAllocFnLibCall(I, TLI); + } SmallVector DefaultAllocFnArgs( {/* Allocated size */ Constant::getNullValue(IntptrTy), /* Number of elements */ Constant::getNullValue(IntptrTy), /* Alignment */ Constant::getNullValue(IntptrTy), /* Old pointer */ Constant::getNullValue(IRB.getInt8PtrTy()),}); + Value *DefaultID = getDefaultID(IRB); + uint64_t LocalId = AllocFnFED.add(*I); + Value *AllocFnId = AllocFnFED.localToGlobalId(LocalId, IRB); + uint64_t AllocFnObjId = AllocFnObj.add(*I, getHeapObject(I)); + assert(LocalId == AllocFnObjId && + "Allocation fn received different ID's in FED and object tables."); + CsiAllocFnProperty Prop; Value *DefaultPropVal = Prop.getValue(IRB); LibFunc AllocLibF; diff --git a/llvm/lib/Transforms/Instrumentation/ComprehensiveStaticInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/ComprehensiveStaticInstrumentation.cpp index 9ded743a83089c..265025ea7bdc55 100644 --- a/llvm/lib/Transforms/Instrumentation/ComprehensiveStaticInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/ComprehensiveStaticInstrumentation.cpp @@ -47,7 +47,6 @@ #include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/TapirUtils.h" -#include "llvm/Support/CommandLine.h" using namespace llvm; @@ -235,17 +234,6 @@ static void setInstrumentationDebugLoc(BasicBlock &Instrumented, } } -/// Set DebugLoc on the call instruction to a CSI hook, based on the -/// debug information of the instrumented instruction. -static void setInstrumentationDebugLoc(Function &Instrumented, - Instruction *Call) { - DISubprogram *Subprog = Instrumented.getSubprogram(); - if (Subprog) { - LLVMContext &C = Instrumented.getParent()->getContext(); - Call->setDebugLoc(DILocation::get(C, 0, 0, Subprog)); - } -} - bool CSIImpl::callsPlaceholderFunction(const Instruction &I) { if (isa(I)) return true; @@ -382,7 +370,7 @@ uint64_t SizeTable::add(const BasicBlock &BB, TargetTransformInfo *TTI) { for (const Instruction &I : BB) { if (TTI) { int ICost = - TTI->getInstructionCost(&I, TargetTransformInfo::TCK_RecipThroughput); + TTI->getInstructionCost(&I, TargetTransformInfo::TCK_Latency); if (-1 == ICost) IRCost += static_cast(TargetTransformInfo::TCC_Basic); else @@ -763,7 +751,6 @@ static void setupBlock(BasicBlock *BB, const TargetLibraryInfo *TLI, return; SmallVector DetachPreds; - SmallVector DetRethrowPreds; SmallVector TFResumePreds; SmallVector SyncPreds; SmallVector SyncUnwindPreds; @@ -774,10 +761,10 @@ static void setupBlock(BasicBlock *BB, const TargetLibraryInfo *TLI, // Partition the predecessors of the landing pad. for (BasicBlock *Pred : predecessors(BB)) { - if (isa(Pred->getTerminator())) + if (isa(Pred->getTerminator()) || + isa(Pred->getTerminator()) || + isDetachedRethrow(Pred->getTerminator())) DetachPreds.push_back(Pred); - else if (isDetachedRethrow(Pred->getTerminator())) - DetRethrowPreds.push_back(Pred); else if (isTaskFrameResume(Pred->getTerminator())) TFResumePreds.push_back(Pred); else if (isa(Pred->getTerminator())) @@ -793,7 +780,6 @@ static void setupBlock(BasicBlock *BB, const TargetLibraryInfo *TLI, } NumPredTypes = static_cast(!DetachPreds.empty()) + - static_cast(!DetRethrowPreds.empty()) + static_cast(!TFResumePreds.empty()) + static_cast(!SyncPreds.empty()) + static_cast(!SyncUnwindPreds.empty()) + @@ -830,13 +816,6 @@ static void setupBlock(BasicBlock *BB, const TargetLibraryInfo *TLI, BBToSplit = SplitOffPreds(BBToSplit, DetachPreds, DT, LI); NumPredTypes--; } - // There is no need to split off detached-rethrow predecessors, since those - // successors of a detached-rethrow are dead up to where control flow merges - // with the unwind destination of a detach. - // if (!DetRethrowPreds.empty() && NumPredTypes > 1) { - // BBToSplit = SplitOffPreds(BBToSplit, DetRethrowPreds, DT, LI); - // NumPredTypes--; - // } } // Setup all basic blocks such that each block's predecessors belong entirely to @@ -848,9 +827,10 @@ void CSIImpl::setupBlocks(Function &F, const TargetLibraryInfo *TLI, if (BB.isLandingPad()) BlocksToSetup.insert(&BB); - if (InvokeInst *II = dyn_cast(BB.getTerminator())) - BlocksToSetup.insert(II->getNormalDest()); - else if (SyncInst *SI = dyn_cast(BB.getTerminator())) + if (InvokeInst *II = dyn_cast(BB.getTerminator())) { + if (!isTapirPlaceholderSuccessor(II->getNormalDest())) + BlocksToSetup.insert(II->getNormalDest()); + } else if (SyncInst *SI = dyn_cast(BB.getTerminator())) BlocksToSetup.insert(SI->getSuccessor(0)); } @@ -1227,6 +1207,15 @@ static void getTaskExits(DetachInst *DI, } } +BasicBlock::iterator +CSIImpl::getFirstInsertionPtInDetachedBlock(BasicBlock *Detached) { + for (Instruction &I : *Detached) + if (IntrinsicInst *II = dyn_cast(&I)) + if (Intrinsic::taskframe_use == II->getIntrinsicID()) + return ++(II->getIterator()); + return Detached->getFirstInsertionPt(); +} + void CSIImpl::instrumentDetach(DetachInst *DI, DominatorTree *DT, TaskInfo &TI, LoopInfo &LI, const DenseMap &TrackVars) { @@ -1339,6 +1328,11 @@ void CSIImpl::instrumentDetach(DetachInst *DI, DominatorTree *DT, TaskInfo &TI, insertHookCallInSuccessorBB(UnwindBlock, PredBlock, CsiDetachContinue, {ContinueID, DetachID, ContProp.getValue(C)}, {DefaultID, DefaultID, DefaultPropVal}); + for (BasicBlock *DRPred : predecessors(UnwindBlock)) + if (isDetachedRethrow(DRPred->getTerminator(), DI->getSyncRegion())) + insertHookCallInSuccessorBB(UnwindBlock, DRPred, CsiDetachContinue, + {ContinueID, DetachID, ContProp.getValue(C)}, + {DefaultID, DefaultID, DefaultPropVal}); } } @@ -1357,15 +1351,11 @@ void CSIImpl::instrumentSync(SyncInst *SI, BasicBlock *SyncBB = SI->getParent(); BasicBlock *SyncCont = SI->getSuccessor(0); BasicBlock *SyncUnwind = nullptr; - if (InvokeInst *II = - dyn_cast(SyncCont->getFirstNonPHIOrDbgOrLifetime())) { - if (const Function *Called = II->getCalledFunction()) { - if (Intrinsic::sync_unwind == Called->getIntrinsicID()) { - SyncBB = SyncCont; - SyncUnwind = II->getUnwindDest(); - SyncCont = II->getNormalDest(); - } - } + if (SyncsWithUnwinds.count(SI)) { + InvokeInst *II = dyn_cast(SyncCont->getTerminator()); + SyncBB = SyncCont; + SyncUnwind = II->getUnwindDest(); + SyncCont = II->getNormalDest(); } CallInst *Call = insertHookCallInSuccessorBB( @@ -1436,24 +1426,19 @@ void CSIImpl::instrumentAlloca(Instruction *I) { insertHookCall(&*Iter, CsiAfterAlloca, {CsiId, Addr, SizeVal, PropVal}); } -void CSIImpl::getAllocFnArgs(const Instruction *I, +bool CSIImpl::getAllocFnArgs(const Instruction *I, SmallVectorImpl &AllocFnArgs, Type *SizeTy, Type *AddrTy, const TargetLibraryInfo &TLI) { - const Function *Called = nullptr; - if (const CallInst *CI = dyn_cast(I)) - Called = CI->getCalledFunction(); - else if (const InvokeInst *II = dyn_cast(I)) - Called = II->getCalledFunction(); - + const Function *Called = dyn_cast(I)->getCalledFunction(); LibFunc F; bool FoundLibFunc = TLI.getLibFunc(*Called, F); if (!FoundLibFunc) - return; + return false; switch (F) { default: - return; + return false; case LibFunc_malloc: case LibFunc_valloc: case LibFunc_Znwj: @@ -1483,7 +1468,7 @@ void CSIImpl::getAllocFnArgs(const Instruction *I, AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; } case LibFunc_ZnwjSt11align_val_t: case LibFunc_ZnwmSt11align_val_t: @@ -1511,7 +1496,7 @@ void CSIImpl::getAllocFnArgs(const Instruction *I, // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); } - return; + return true; } case LibFunc_calloc: { const CallInst *CI = cast(I); @@ -1523,7 +1508,7 @@ void CSIImpl::getAllocFnArgs(const Instruction *I, AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; } case LibFunc_realloc: case LibFunc_reallocf: { @@ -1536,7 +1521,7 @@ void CSIImpl::getAllocFnArgs(const Instruction *I, AllocFnArgs.push_back(ConstantInt::get(SizeTy, 0)); // Old pointer AllocFnArgs.push_back(CI->getArgOperand(0)); - return; + return true; } case LibFunc_aligned_alloc: { const CallInst *CI = cast(I); @@ -1548,7 +1533,7 @@ void CSIImpl::getAllocFnArgs(const Instruction *I, AllocFnArgs.push_back(CI->getArgOperand(0)); // Old pointer = NULL AllocFnArgs.push_back(Constant::getNullValue(AddrTy)); - return; + return true; } } } @@ -2016,6 +2001,8 @@ CallInst *CSIImpl::createRTUnitInitCall(IRBuilder<> &IRB) { FunctionType *InitFunctionTy = FunctionType::get(IRB.getVoidTy(), InitArgTypes, false); RTUnitInit = M.getOrInsertFunction(CsiRtUnitInitName, InitFunctionTy); + assert(isa(RTUnitInit.getCallee()) && + "Failed to get or insert __csirt_unit_init function"); ArrayType *UnitFedTableArrayType = ArrayType::get(UnitFedTableType, UnitFedTables.size()); @@ -2065,8 +2052,8 @@ void CSIImpl::finalizeCsi() { appendToGlobalCtors(M, Ctor, CsiUnitCtorPriority); CallGraphNode *CNCtor = CG->getOrInsertFunction(Ctor); - CallGraphNode *CNFunc = CG->getOrInsertFunction( - cast(RTUnitInit.getCallee())); + CallGraphNode *CNFunc = + CG->getOrInsertFunction(cast(RTUnitInit.getCallee())); CNCtor->addCalledFunction(Call, CNFunc); } } @@ -2179,11 +2166,20 @@ bool CSIImpl::shouldNotInstrumentFunction(Function &F) { if (F.hasName() && F.getName() == CsiRtUnitCtorName) return true; + // Don't instrument anything in the startup section or the __StaticInit + // section (MacOSX). + if (F.getSection() == ".text.startup" || + F.getSection().find("__StaticInit") != std::string::npos) + return true; + // Don't instrument functions that will run before or // simultaneously with CSI ctors. GlobalVariable *GV = M.getGlobalVariable("llvm.global_ctors"); if (GV == nullptr) return false; + if (!GV->hasInitializer() || GV->getInitializer()->isNullValue()) + return false; + ConstantArray *CA = cast(GV->getInitializer()); for (Use &OP : CA->operands()) { if (isa(OP)) @@ -2321,8 +2317,6 @@ void CSIImpl::instrumentFunction(Function &F) { setupCalls(F); const TargetLibraryInfo *TLI = &GetTLI(F); - // Canonicalize the CFG for CSI instrumentation - setupBlocks(F, TLI); // If we do not assume that calls terminate blocks, or if we're not // instrumenting basic blocks, then we're done. @@ -2331,10 +2325,15 @@ void CSIImpl::instrumentFunction(Function &F) { DominatorTree *DT = &GetDomTree(F); LoopInfo &LI = GetLoopInfo(F); + if (Options.InstrumentLoops) + // Simplify loops to prepare for loop instrumentation for (Loop *L : LI) simplifyLoop(L, DT, &LI, nullptr, nullptr, nullptr, - /* PreserveLCSSA */false); + /* PreserveLCSSA */ false); + + // Canonicalize the CFG for CSI instrumentation + setupBlocks(F, TLI, DT, &LI); LLVM_DEBUG(dbgs() << "Canonicalized function:\n" << F); @@ -2351,6 +2350,7 @@ void CSIImpl::instrumentFunction(Function &F) { SmallVector Allocas; SmallVector AllCalls; bool MaySpawn = false; + SmallPtrSet BBsToIgnore; TaskInfo &TI = GetTaskInfo(F); ScalarEvolution *SE = nullptr; @@ -2359,6 +2359,9 @@ void CSIImpl::instrumentFunction(Function &F) { // Compile lists of all instrumentation points before anything is modified. for (BasicBlock &BB : F) { + // Ignore Tapir placeholder basic blocks + if (&F.getEntryBlock() != &BB && isTapirPlaceholderSuccessor(&BB)) + continue; SmallVector BBLoadsAndStores; for (Instruction &I : BB) { if (isAtomic(&I)) @@ -2370,8 +2373,12 @@ void CSIImpl::instrumentFunction(Function &F) { Detaches.push_back(DI); } else if (SyncInst *SI = dyn_cast(&I)) { Syncs.push_back(SI); - } else if (isa(I) || isa(I)) { - + if (isSyncUnwind( + SI->getSuccessor(0)->getFirstNonPHIOrDbgOrLifetime())) { + SyncsWithUnwinds.insert(SI); + BBsToIgnore.insert(SI->getSuccessor(0)); + } + } else if (isa(I)) { // Record this function call as either an allocation function, a call to // free (or delete), a memory intrinsic, or an ordinary real function // call. @@ -2381,7 +2388,7 @@ void CSIImpl::instrumentFunction(Function &F) { FreeCalls.push_back(&I); else if (isa(I)) MemIntrinsics.push_back(&I); - else + else if (!callsPlaceholderFunction(I)) Callsites.push_back(&I); AllCalls.push_back(&I); @@ -2392,7 +2399,8 @@ void CSIImpl::instrumentFunction(Function &F) { } } computeLoadAndStoreProperties(LoadAndStoreProperties, BBLoadsAndStores); - BasicBlocks.push_back(&BB); + if (!BBsToIgnore.count(&BB)) + BasicBlocks.push_back(&BB); } uint64_t LocalId = getLocalFunctionID(F); diff --git a/llvm/lib/Transforms/Utils/TapirUtils.cpp b/llvm/lib/Transforms/Utils/TapirUtils.cpp index 56c6648e0baa8b..c235a9282eeb9e 100644 --- a/llvm/lib/Transforms/Utils/TapirUtils.cpp +++ b/llvm/lib/Transforms/Utils/TapirUtils.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/TapirUtils.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/TapirTaskInfo.h" @@ -56,6 +57,21 @@ bool llvm::isTaskFrameResume(const Instruction *I, const Value *TaskFrame) { isTapirIntrinsic(Intrinsic::taskframe_resume, I, TaskFrame); } +/// Returns true if the given basic block \p B is a placeholder successor of a +/// taskframe.resume or detached.rethrow. +bool llvm::isTapirPlaceholderSuccessor(const BasicBlock *B) { + for (const BasicBlock *Pred : predecessors(B)) { + if (!isDetachedRethrow(Pred->getTerminator()) && + !isTaskFrameResume(Pred->getTerminator())) + return false; + + const InvokeInst *II = dyn_cast(Pred->getTerminator()); + if (B != II->getNormalDest()) + return false; + } + return true; +} + /// Returns a taskframe.resume that uses the given taskframe, or nullptr if no /// taskframe.resume uses this taskframe. InvokeInst *llvm::getTaskFrameResume(Value *TaskFrame) { @@ -1174,11 +1190,7 @@ bool llvm::mayBeUnsynced(const BasicBlock *BB) { // that detach spawned the current basic block. if (isa(PredBB->getTerminator())) { const DetachInst *DI = cast(PredBB->getTerminator()); - if (DI->getDetached() == CurrBB) - // Return the current block, which is the entry of this detached - // sub-CFG. - continue; - else + if (DI->getDetached() != CurrBB) // We encountered a continue or unwind destination of a detach. // Conservatively return that we may not be synced. return true; @@ -1486,6 +1498,7 @@ bool llvm::splitTaskFrameCreateBlocks(Function &F, DominatorTree *DT, SmallVector TFCreateToSplit; SmallVector DetachesWithTaskFrames; SmallVector TFEndToSplit; + SmallVector TFResumeToSplit; SmallVector WorkList; SmallPtrSet Visited; WorkList.push_back(&F.getEntryBlock()); @@ -1517,7 +1530,11 @@ bool llvm::splitTaskFrameCreateBlocks(Function &F, DominatorTree *DT, } else if (Intrinsic::taskframe_end == UI->getIntrinsicID()) { // Record this taskframe.end. TFEndToSplit.push_back(UI); - break; + } + } else if (Instruction *UI = dyn_cast(U)) { + if (isTaskFrameResume(UI, II)) { + // Record this taskframe.resume. + TFResumeToSplit.push_back(UI); } } } @@ -1553,7 +1570,7 @@ bool llvm::splitTaskFrameCreateBlocks(Function &F, DominatorTree *DT, Changed = true; } - // Also split critical continue edges, if we need to. For example, we need to + // Split critical continue edges, if we need to. For example, we need to // split critical continue edges if we're planning to fixup external uses of // variables defined in a taskframe. // @@ -1567,6 +1584,16 @@ bool llvm::splitTaskFrameCreateBlocks(Function &F, DominatorTree *DT, Changed = true; } } + // Similarly, split unwind edges from taskframe.resume's. + for (Instruction *TFResume : TFResumeToSplit) { + InvokeInst *II = cast(TFResume); + if (DT && isCriticalEdge(II, 1)) { + BasicBlock *Unwind = II->getUnwindDest(); + SplitBlockPredecessors(Unwind, {II->getParent()}, ".tfsplit", DT, nullptr, + nullptr); + Changed = true; + } + } // Recalculate TaskInfo if necessary. if (Changed && DT && TI) @@ -1836,15 +1863,26 @@ BasicBlock *llvm::CreateSubTaskUnwindEdge(Intrinsic::ID TermFunc, Value *Token, } static BasicBlock *MaybePromoteCallInBlock(BasicBlock *BB, - BasicBlock *UnwindEdge) { - for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E; ) { + BasicBlock *UnwindEdge, + const Value *TaskFrame) { + for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;) { Instruction *I = &*BBI++; // We only need to check for function calls: inlined invoke // instructions require no special handling. CallInst *CI = dyn_cast(I); - if (!CI || CI->doesNotThrow() || isa(CI->getCalledValue())) + if (!CI || isa(CI->getCalledValue())) + continue; + + // Stop the search early if we encounter a taskframe.create or a + // taskframe.end. + if (isTapirIntrinsic(Intrinsic::taskframe_create, CI) || + (TaskFrame && + isTapirIntrinsic(Intrinsic::taskframe_end, CI, TaskFrame))) + return nullptr; + + if (CI->doesNotThrow()) continue; // We do not need to (and in fact, cannot) convert possibly throwing calls @@ -1864,6 +1902,28 @@ static BasicBlock *MaybePromoteCallInBlock(BasicBlock *BB, return nullptr; } +static Instruction *GetTaskFrameInstructionInBlock(BasicBlock *BB, + const Value *TaskFrame) { + for (BasicBlock::iterator BBI = BB->begin(), E = BB->end(); BBI != E;) { + Instruction *I = &*BBI++; + + // We only need to check for function calls: inlined invoke + // instructions require no special handling. + CallInst *CI = dyn_cast(I); + + if (!CI || isa(CI->getCalledValue())) + continue; + + // Stop the search early if we encounter a taskframe.create or a + // taskframe.end. + if (isTapirIntrinsic(Intrinsic::taskframe_create, CI) || + (TaskFrame && + isTapirIntrinsic(Intrinsic::taskframe_end, CI, TaskFrame))) + return I; + } + return nullptr; +} + // Recursively handle inlined tasks. static void PromoteCallsInTasksHelper( BasicBlock *EntryBlock, BasicBlock *UnwindEdge, @@ -1881,7 +1941,14 @@ static void PromoteCallsInTasksHelper( if (!Visited.insert(BB).second) continue; - if (Instruction *TFCreate = FindTaskFrameCreateInBlock(BB)) { + // Promote any calls in the block to invokes. + while (BasicBlock *NewBB = + MaybePromoteCallInBlock(BB, UnwindEdge, CurrentTaskFrame)) + BB = cast(NewBB->getTerminator())->getNormalDest(); + + Instruction *TFI = GetTaskFrameInstructionInBlock(BB, CurrentTaskFrame); + if (TFI && isTapirIntrinsic(Intrinsic::taskframe_create, TFI)) { + Instruction *TFCreate = TFI; if (TFCreate != CurrentTaskFrame) { // Split the block at the taskframe.create, if necessary. BasicBlock *NewBB; @@ -1904,11 +1971,14 @@ static void PromoteCallsInTasksHelper( TaskFrameUnwindEdge->eraseFromParent(); continue; } - } - - // Promote any calls in the block to invokes. - while (BasicBlock *NewBB = MaybePromoteCallInBlock(BB, UnwindEdge)) { - BB = cast(NewBB->getTerminator())->getNormalDest(); + } else if (TFI && isTapirIntrinsic(Intrinsic::taskframe_end, TFI, + CurrentTaskFrame)) { + // If we find a taskframe.end in this block that ends the current + // taskframe, add this block to the parent search. + assert(ParentWorklist && + "Unexpected taskframe.resume: no parent worklist"); + ParentWorklist->push_back(BB); + continue; } // Ignore reattach terminators. @@ -1916,14 +1986,6 @@ static void PromoteCallsInTasksHelper( isDetachedRethrow(BB->getTerminator())) continue; - // If we find a taskframe.end, add its successor to the parent search. - if (endsTaskFrame(BB, CurrentTaskFrame)) { - assert(ParentWorklist && - "Unexpected taskframe.resume: no parent worklist"); - ParentWorklist->push_back(BB->getSingleSuccessor()); - continue; - } - // If we find a taskframe.resume terminator, add its successor to the // parent search. if (isTaskFrameResume(BB->getTerminator())) { @@ -1955,9 +2017,9 @@ static void PromoteCallsInTasksHelper( DetachesToReplace.push_back(DI); } else { - PromoteCallsInTasksHelper(DI->getDetached(), DI->getUnwindDest(), - Unreachable, CurrentTaskFrame, &Worklist); - + // Because this detach has an unwind destination, Any calls in the + // spawned task that may throw should already be invokes. Hence there + // is no need to promote calls in this task. if (Visited.insert(DI->getUnwindDest()).second) // If the detach-unwind isn't dead, add it to the worklist. Worklist.push_back(DI->getUnwindDest()); @@ -2251,7 +2313,6 @@ void llvm::TapirLoopHints::clearHintsMetadata() { bool llvm::hintsDemandOutlining(const TapirLoopHints &Hints) { switch (Hints.getStrategy()) { case TapirLoopHints::ST_DAC: return true; - case TapirLoopHints::ST_OCL: return true; default: return false; } } diff --git a/llvm/projects/CMakeLists.txt b/llvm/projects/CMakeLists.txt index f6d2f760f785c2..fc865da500dfa6 100644 --- a/llvm/projects/CMakeLists.txt +++ b/llvm/projects/CMakeLists.txt @@ -13,7 +13,8 @@ foreach(entry ${entries}) (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/parallel-libs) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/openmp) AND (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/debuginfo-tests) AND - (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/cheetah)) + (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/cheetah) + (NOT ${entry} STREQUAL ${CMAKE_CURRENT_SOURCE_DIR}/cliktools)) get_filename_component(entry_name "${entry}" NAME) add_llvm_external_project(${entry_name}) endif() @@ -30,6 +31,7 @@ if(${LLVM_BUILD_RUNTIME}) if(NOT MSVC OR LLVM_FORCE_BUILD_RUNTIME) # Add the projects in reverse order of their dependencies so that the # dependent projects can see the target names of their dependencies. + add_llvm_external_project(cilktools) add_llvm_external_project(cheetah) add_llvm_external_project(libunwind) add_llvm_external_project(pstl) diff --git a/llvm/runtimes/CMakeLists.txt b/llvm/runtimes/CMakeLists.txt index 6a4a76918b0710..267af4648e9b05 100644 --- a/llvm/runtimes/CMakeLists.txt +++ b/llvm/runtimes/CMakeLists.txt @@ -17,6 +17,11 @@ FetchContent_Declare(cheetahrt GIT_TAG opencilk/v1.0 SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../cheetah) +FetchContent_Declare(cilktools + GIT_REPOSITORY https://github.com/OpenCilk/productivity-tools.git + GIT_TAG opencilk/v1.0 + SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../cilktools) + # Find all subdirectories containing CMake projects file(GLOB entries *) foreach(entry ${entries}) @@ -26,7 +31,7 @@ foreach(entry ${entries}) endforeach() # Side-by-side subprojects layout. -set(LLVM_ALL_RUNTIMES "libcxx;libcxxabi;libunwind;compiler-rt;cheetah;kitsune") +set(LLVM_ALL_RUNTIMES "libcxx;libcxxabi;libunwind;compiler-rt;cheetah;cilktools;kitsune") set(LLVM_ENABLE_RUNTIMES "" CACHE STRING "Semicolon-separated list of runtimes to build (${LLVM_ALL_RUNTIMES}), or \"all\".") if(LLVM_ENABLE_RUNTIMES STREQUAL "all" ) @@ -41,6 +46,14 @@ if ("cheetah" IN_LIST LLVM_ENABLE_RUNTIMES) endif() endif() +if ("cilktools" IN_LIST LLVM_ENABLE_RUNTIMES) + FetchContent_GetProperties(cilktools) + if (NOT cilktools_POPULATED) + message(STATUS "NOTE: <<<< fetching cilktools source via git... >>>>") + FetchContent_Populate(cilktools) + endif() +endif() + foreach(proj ${LLVM_ENABLE_RUNTIMES}) set(proj_dir "${CMAKE_CURRENT_SOURCE_DIR}/../../${proj}") if(IS_DIRECTORY ${proj_dir} AND EXISTS ${proj_dir}/CMakeLists.txt)