diff --git a/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp index 3b5eef0900c7..989153b46e63 100644 --- a/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/CilkSanitizer.cpp @@ -39,8 +39,10 @@ #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/ProfileData/InstrProf.h" @@ -587,6 +589,7 @@ struct CilkSanitizerImpl : public CSIImpl { } FunctionCallee getOrInsertSynthesizedHook(StringRef Name, FunctionType *T, + int ReturnParam = -1, AttributeList AL = AttributeList()); }; @@ -3668,6 +3671,7 @@ bool CilkSanitizerImpl::instrumentAtomic(Instruction *I, IRBuilder<> &IRB) { FunctionCallee CilkSanitizerImpl::getOrInsertSynthesizedHook(StringRef Name, FunctionType *T, + int ReturnParam, AttributeList AL) { // If no bitcode file has been linked, then we cannot check if it contains a // particular library hook. Simply return the hook. If the Cilksan library @@ -3680,14 +3684,28 @@ FunctionCallee CilkSanitizerImpl::getOrInsertSynthesizedHook(StringRef Name, if (FunctionsInBitcode.contains(std::string(Name))) return getHookFunction(Name, T, AL); + // If the function is already present, just return it. + if (Function *F = M.getFunction(Name)) + if (F->getFunctionType() == T) + return M.getOrInsertFunction(Name, T); + // We did not find the library hook in the linked bitcode file. Synthesize a // default version of the hook that simply calls __csan_default_libhook. FunctionCallee NewHook = M.getOrInsertFunction(Name, T, AL); Function *NewHookFn = cast(NewHook.getCallee()); NewHookFn->setOnlyAccessesInaccessibleMemOrArgMem(); NewHookFn->setDoesNotThrow(); - BasicBlock *Entry = BasicBlock::Create(M.getContext(), "entry", NewHookFn); - IRBuilder<> IRB(ReturnInst::Create(M.getContext(), Entry)); + LLVMContext &Ctx = M.getContext(); + assert((T->getReturnType() == Type::getVoidTy(Ctx) || ReturnParam >= 0) && + "Synthesizing hook with return value, but no return parameter " + "specified."); + BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", NewHookFn); + // Return void or the parameter at the specified index. + ReturnInst *RI = + (T->getReturnType() == Type::getVoidTy(Ctx) || ReturnParam < 0) + ? ReturnInst::Create(Ctx, Entry) + : ReturnInst::Create(Ctx, NewHookFn->getArg(ReturnParam), Entry); + IRBuilder<> IRB(RI); // Insert a call to the default library function hook Type *IDType = IRB.getInt64Ty(); @@ -3818,9 +3836,11 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall( // Populate the AfterHook parameters with the parameters of the instrumented // function itself. + int ReturnParam = -1; Value *SavedStack = nullptr; const DataLayout &DL = M.getDataLayout(); if (!Called->getReturnType()->isVoidTy()) { + ReturnParam = AfterHookParamVals.size(); Type *RetTy = Called->getReturnType(); if (!needToSpillType(RetTy)) { // We can simply pass the return value directly to the hook. @@ -3871,8 +3891,8 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall( case Intrinsic::hyper_lookup: { FunctionType *AfterHookTy = FunctionType::get(IRB.getPtrTy(), AfterHookParamTys, Called->isVarArg()); - FunctionCallee AfterIntrinCallHook = - getOrInsertSynthesizedHook(("__csan_" + Buf).str(), AfterHookTy); + FunctionCallee AfterIntrinCallHook = getOrInsertSynthesizedHook( + ("__csan_" + Buf).str(), AfterHookTy, ReturnParam); CallInst *HookCall = insertHookCall(&*Iter, AfterIntrinCallHook, AfterHookParamVals); II->replaceUsesWithIf(HookCall, [HookCall](Use &U) { @@ -3884,8 +3904,8 @@ bool CilkSanitizerImpl::instrumentIntrinsicCall( FunctionType *AfterHookTy = FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); - FunctionCallee AfterIntrinCallHook = - getOrInsertSynthesizedHook(("__csan_" + Buf).str(), AfterHookTy); + FunctionCallee AfterIntrinCallHook = getOrInsertSynthesizedHook( + ("__csan_" + Buf).str(), AfterHookTy, ReturnParam); // Insert the hook call insertHookCall(&*Iter, AfterIntrinCallHook, AfterHookParamVals); @@ -3958,7 +3978,9 @@ bool CilkSanitizerImpl::instrumentLibCall(Instruction *I, {CallsiteId, FuncId, NumMVVal, PropVal}); SmallVector AfterHookDefaultVals( {DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal}); + int ReturnParam = -1; if (!Called->getReturnType()->isVoidTy()) { + ReturnParam = AfterHookParamTys.size(); AfterHookParamTys.push_back(Called->getReturnType()); AfterHookParamVals.push_back(CB); AfterHookDefaultVals.push_back( @@ -3972,7 +3994,7 @@ bool CilkSanitizerImpl::instrumentLibCall(Instruction *I, FunctionType *AfterHookTy = FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook( - ("__csan_" + Called->getName()).str(), AfterHookTy); + ("__csan_" + Called->getName()).str(), AfterHookTy, ReturnParam); BasicBlock::iterator Iter(I); if (IsInvoke) { @@ -4595,7 +4617,9 @@ bool CilkSanitizerImpl::instrumentAllocFnLibCall(Instruction *I, {AllocFnId, FuncId, NumMVVal, PropVal}); SmallVector AfterHookDefaultVals( {DefaultID, DefaultID, IRB.getInt8(0), DefaultPropVal}); + int ReturnParam = -1; if (!Called->getReturnType()->isVoidTy()) { + ReturnParam = AfterHookParamVals.size(); AfterHookParamTys.push_back(Called->getReturnType()); AfterHookParamVals.push_back(CB); AfterHookDefaultVals.push_back( @@ -4609,7 +4633,7 @@ bool CilkSanitizerImpl::instrumentAllocFnLibCall(Instruction *I, FunctionType *AfterHookTy = FunctionType::get(IRB.getVoidTy(), AfterHookParamTys, Called->isVarArg()); FunctionCallee AfterLibCallHook = getOrInsertSynthesizedHook( - ("__csan_alloc_" + Called->getName()).str(), AfterHookTy); + ("__csan_alloc_" + Called->getName()).str(), AfterHookTy, ReturnParam); // Insert the hook after the call. BasicBlock::iterator Iter(I); diff --git a/llvm/test/Transforms/Tapir/CilkSanitizer/cabs-fstat64.ll b/llvm/test/Transforms/Tapir/CilkSanitizer/cabs-fstat64.ll new file mode 100644 index 000000000000..ed4c90391471 --- /dev/null +++ b/llvm/test/Transforms/Tapir/CilkSanitizer/cabs-fstat64.ll @@ -0,0 +1,188 @@ +; Check synthesis of Cilksan hooks for cabs and fstat64. +; Although both of these functions return values, their Cilksan hooks should return void. +; +; RUN: opt < %s -passes="cilksan" -cilksan-bc-path=%S/null-bitcode.bc -S | FileCheck %s +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +module asm ".globl _ZSt21ios_base_library_initv" + +%"class.std::basic_ostream" = type { ptr, %"class.std::basic_ios" } +%"class.std::basic_ios" = type { %"class.std::ios_base", ptr, i8, i8, ptr, ptr, ptr, ptr } +%"class.std::ios_base" = type { ptr, i64, i64, i32, i32, i32, ptr, %"struct.std::ios_base::_Words", [8 x %"struct.std::ios_base::_Words"], i32, ptr, %"class.std::locale" } +%"struct.std::ios_base::_Words" = type { ptr, i64 } +%"class.std::locale" = type { ptr } +%struct.stat64 = type { i64, i64, i64, i32, i32, i32, i32, i64, i64, i64, i64, %struct.timespec, %struct.timespec, %struct.timespec, [3 x i64] } +%struct.timespec = type { i64, i64 } +%"class.std::ctype" = type <{ %"class.std::locale::facet.base", [4 x i8], ptr, i8, [7 x i8], ptr, ptr, ptr, i8, [256 x i8], [256 x i8], i8, [6 x i8] }> +%"class.std::locale::facet.base" = type <{ ptr, i32 }> + +@_ZSt4cout = external global %"class.std::basic_ostream", align 8 + +; Function Attrs: mustprogress norecurse sanitize_cilk uwtable +define dso_local noundef i32 @main() local_unnamed_addr #0 { +entry: + %buf = alloca %struct.stat64, align 8 + %call.i.i = tail call noundef double @cabs(double noundef 1.000000e+00, double noundef 2.000000e+00) #5 + %call.i = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertIdEERSoT_(ptr noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, double noundef %call.i.i) + %vtable.i = load ptr, ptr %call.i, align 8, !tbaa !5 + %vbase.offset.ptr.i = getelementptr i8, ptr %vtable.i, i64 -24 + %vbase.offset.i = load i64, ptr %vbase.offset.ptr.i, align 8 + %add.ptr.i = getelementptr inbounds i8, ptr %call.i, i64 %vbase.offset.i + %_M_ctype.i.i = getelementptr inbounds %"class.std::basic_ios", ptr %add.ptr.i, i64 0, i32 5 + %0 = load ptr, ptr %_M_ctype.i.i, align 8, !tbaa !8 + %tobool.not.i.i.i = icmp eq ptr %0, null + br i1 %tobool.not.i.i.i, label %if.then.i.i.i, label %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i + +if.then.i.i.i: ; preds = %entry + tail call void @_ZSt16__throw_bad_castv() #6 + unreachable + +_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i: ; preds = %entry + %_M_widen_ok.i.i.i = getelementptr inbounds %"class.std::ctype", ptr %0, i64 0, i32 8 + %1 = load i8, ptr %_M_widen_ok.i.i.i, align 8, !tbaa !20 + %tobool.not.i1.i.i = icmp eq i8 %1, 0 + br i1 %tobool.not.i1.i.i, label %if.end.i.i.i, label %if.then.i2.i.i + +if.then.i2.i.i: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i + %arrayidx.i.i.i = getelementptr inbounds %"class.std::ctype", ptr %0, i64 0, i32 9, i64 10 + %2 = load i8, ptr %arrayidx.i.i.i, align 1, !tbaa !23 + br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit + +if.end.i.i.i: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i + tail call void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570) %0) + %vtable.i.i.i = load ptr, ptr %0, align 8, !tbaa !5 + %vfn.i.i.i = getelementptr inbounds ptr, ptr %vtable.i.i.i, i64 6 + %3 = load ptr, ptr %vfn.i.i.i, align 8 + %call.i.i.i = tail call noundef signext i8 %3(ptr noundef nonnull align 8 dereferenceable(570) %0, i8 noundef signext 10) + br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit + +_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit: ; preds = %if.then.i2.i.i, %if.end.i.i.i + %retval.0.i.i.i = phi i8 [ %2, %if.then.i2.i.i ], [ %call.i.i.i, %if.end.i.i.i ] + %call1.i = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8) %call.i, i8 noundef signext %retval.0.i.i.i) + %call.i.i4 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8) %call1.i) + call void @llvm.lifetime.start.p0(i64 144, ptr nonnull %buf) #5 + %call3 = call i32 @fstat64(i32 noundef 0, ptr noundef nonnull %buf) #5 + %4 = load i64, ptr %buf, align 8, !tbaa !24 + %call.i2 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertImEERSoT_(ptr noundef nonnull align 8 dereferenceable(8) @_ZSt4cout, i64 noundef %4) + %vtable.i5 = load ptr, ptr %call.i2, align 8, !tbaa !5 + %vbase.offset.ptr.i6 = getelementptr i8, ptr %vtable.i5, i64 -24 + %vbase.offset.i7 = load i64, ptr %vbase.offset.ptr.i6, align 8 + %add.ptr.i8 = getelementptr inbounds i8, ptr %call.i2, i64 %vbase.offset.i7 + %_M_ctype.i.i9 = getelementptr inbounds %"class.std::basic_ios", ptr %add.ptr.i8, i64 0, i32 5 + %5 = load ptr, ptr %_M_ctype.i.i9, align 8, !tbaa !8 + %tobool.not.i.i.i10 = icmp eq ptr %5, null + br i1 %tobool.not.i.i.i10, label %if.then.i.i.i23, label %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11 + +if.then.i.i.i23: ; preds = %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit + tail call void @_ZSt16__throw_bad_castv() #6 + unreachable + +_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11: ; preds = %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit + %_M_widen_ok.i.i.i12 = getelementptr inbounds %"class.std::ctype", ptr %5, i64 0, i32 8 + %6 = load i8, ptr %_M_widen_ok.i.i.i12, align 8, !tbaa !20 + %tobool.not.i1.i.i13 = icmp eq i8 %6, 0 + br i1 %tobool.not.i1.i.i13, label %if.end.i.i.i19, label %if.then.i2.i.i14 + +if.then.i2.i.i14: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11 + %arrayidx.i.i.i15 = getelementptr inbounds %"class.std::ctype", ptr %5, i64 0, i32 9, i64 10 + %7 = load i8, ptr %arrayidx.i.i.i15, align 1, !tbaa !23 + br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24 + +if.end.i.i.i19: ; preds = %_ZSt13__check_facetISt5ctypeIcEERKT_PS3_.exit.i.i11 + tail call void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570) %5) + %vtable.i.i.i20 = load ptr, ptr %5, align 8, !tbaa !5 + %vfn.i.i.i21 = getelementptr inbounds ptr, ptr %vtable.i.i.i20, i64 6 + %8 = load ptr, ptr %vfn.i.i.i21, align 8 + %call.i.i.i22 = tail call noundef signext i8 %8(ptr noundef nonnull align 8 dereferenceable(570) %5, i8 noundef signext 10) + br label %_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24 + +_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_.exit24: ; preds = %if.then.i2.i.i14, %if.end.i.i.i19 + %retval.0.i.i.i16 = phi i8 [ %7, %if.then.i2.i.i14 ], [ %call.i.i.i22, %if.end.i.i.i19 ] + %call1.i17 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8) %call.i2, i8 noundef signext %retval.0.i.i.i16) + %call.i.i18 = tail call noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8) %call1.i17) + call void @llvm.lifetime.end.p0(i64 144, ptr nonnull %buf) #5 + ret i32 0 +} + +; CHECK: define {{.*}}i32 @main() +; CHECK: %[[CABS_CALL:.+]] = {{.*}}call {{.*}}double @cabs(double noundef 1.000000e+00, double noundef 2.000000e+00) +; CHECK-NEXT: call {{.*}}void @__csan_cabs(i64 %{{.+}}, i64 %{{.+}}, i8 0, i64 0, double %[[CABS_CALL]], double 1.000000e+00, double 2.000000e+00) +; CHECK: %call3 = call {{.*}}i32 @fstat64(i32 noundef 0, ptr {{.*}}%[[BUF:.+]]) +; CHECK-NEXT: call {{.*}}void @__csan_fstat64(i64 %{{.+}}, i64 %{{.+}}, i8 1, i64 0, i32 %call3, i32 0, ptr {{.*}}%[[BUF]]) + +; CHECK: define {{.*}}void @__csan_cabs(i64 %0, i64 %1, i8 %2, i64 %3, double %4, double %5, double %6) +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @__csan_default_libhook(i64 %0, i64 %1, i8 %2) +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; CHECK: define {{.*}}void @__csan_fstat64(i64 %0, i64 %1, i8 %2, i64 %3, i32 %4, i32 %5, ptr %6) +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @__csan_default_libhook(i64 %0, i64 %1, i8 %2) +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: nofree nounwind +declare noundef i32 @fstat64(i32 noundef, ptr nocapture noundef) local_unnamed_addr #2 + +; Function Attrs: nofree nounwind +declare double @cabs(double noundef, double noundef) local_unnamed_addr #2 + +declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertIdEERSoT_(ptr noundef nonnull align 8 dereferenceable(8), double noundef) local_unnamed_addr #3 + +declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo3putEc(ptr noundef nonnull align 8 dereferenceable(8), i8 noundef signext) local_unnamed_addr #3 + +declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo5flushEv(ptr noundef nonnull align 8 dereferenceable(8)) local_unnamed_addr #3 + +; Function Attrs: cold noreturn +declare void @_ZSt16__throw_bad_castv() local_unnamed_addr #4 + +declare void @_ZNKSt5ctypeIcE13_M_widen_initEv(ptr noundef nonnull align 8 dereferenceable(570)) local_unnamed_addr #3 + +declare noundef nonnull align 8 dereferenceable(8) ptr @_ZNSo9_M_insertImEERSoT_(ptr noundef nonnull align 8 dereferenceable(8), i64 noundef) local_unnamed_addr #3 + +attributes #0 = { mustprogress norecurse sanitize_cilk uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #2 = { nofree nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #4 = { cold noreturn "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #5 = { nounwind } +attributes #6 = { cold noreturn } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{!"clang version 18.1.8 (git@github.com:neboat/opencilk-project.git c3cd84365e099ab6dfa4b484475ef66f33f16eab)"} +!5 = !{!6, !6, i64 0} +!6 = !{!"vtable pointer", !7, i64 0} +!7 = !{!"Simple C++ TBAA"} +!8 = !{!9, !15, i64 240} +!9 = !{!"_ZTSSt9basic_iosIcSt11char_traitsIcEE", !10, i64 0, !15, i64 216, !12, i64 224, !19, i64 225, !15, i64 232, !15, i64 240, !15, i64 248, !15, i64 256} +!10 = !{!"_ZTSSt8ios_base", !11, i64 8, !11, i64 16, !13, i64 24, !14, i64 28, !14, i64 32, !15, i64 40, !16, i64 48, !12, i64 64, !17, i64 192, !15, i64 200, !18, i64 208} +!11 = !{!"long", !12, i64 0} +!12 = !{!"omnipotent char", !7, i64 0} +!13 = !{!"_ZTSSt13_Ios_Fmtflags", !12, i64 0} +!14 = !{!"_ZTSSt12_Ios_Iostate", !12, i64 0} +!15 = !{!"any pointer", !12, i64 0} +!16 = !{!"_ZTSNSt8ios_base6_WordsE", !15, i64 0, !11, i64 8} +!17 = !{!"int", !12, i64 0} +!18 = !{!"_ZTSSt6locale", !15, i64 0} +!19 = !{!"bool", !12, i64 0} +!20 = !{!21, !12, i64 56} +!21 = !{!"_ZTSSt5ctypeIcE", !22, i64 0, !15, i64 16, !19, i64 24, !15, i64 32, !15, i64 40, !15, i64 48, !12, i64 56, !12, i64 57, !12, i64 313, !12, i64 569} +!22 = !{!"_ZTSNSt6locale5facetE", !17, i64 8} +!23 = !{!12, !12, i64 0} +!24 = !{!25, !11, i64 0} +!25 = !{!"_ZTS6stat64", !11, i64 0, !11, i64 8, !11, i64 16, !17, i64 24, !17, i64 28, !17, i64 32, !17, i64 36, !11, i64 40, !11, i64 48, !11, i64 56, !11, i64 64, !26, i64 72, !26, i64 88, !26, i64 104, !12, i64 120} +!26 = !{!"_ZTS8timespec", !11, i64 0, !11, i64 8} diff --git a/llvm/test/Transforms/Tapir/CilkSanitizer/hyper-lookup-synthesized-hooks.ll b/llvm/test/Transforms/Tapir/CilkSanitizer/hyper-lookup-synthesized-hooks.ll new file mode 100644 index 000000000000..c17c0a75a6da --- /dev/null +++ b/llvm/test/Transforms/Tapir/CilkSanitizer/hyper-lookup-synthesized-hooks.ll @@ -0,0 +1,125 @@ +; Check synthesis of hooks for hyper.lookup calls. +; +; RUN: opt < %s -passes="cilksan" -cilksan-bc-path=%S/null-bitcode.bc -S | FileCheck %s +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +$_Z8sum_initIdEvPv = comdat any + +$_Z10sum_reduceIdEvPvS0_ = comdat any + +; Function Attrs: mustprogress sanitize_cilk uwtable +define dso_local void @_Z3runv() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 { +entry: + %sumAParRelError = alloca double, align 8 + call void @llvm.lifetime.start.p0(i64 8, ptr nonnull %sumAParRelError) #7 + store double 0.000000e+00, ptr %sumAParRelError, align 8, !tbaa !5 + call void @llvm.reducer.register.i64(ptr nonnull %sumAParRelError, i64 8, ptr nonnull @_Z8sum_initIdEvPv, ptr nonnull @_Z10sum_reduceIdEvPvS0_) + %0 = call ptr @llvm.hyper.lookup.i64(ptr nonnull %sumAParRelError, i64 8, ptr nonnull @_Z8sum_initIdEvPv, ptr nonnull @_Z10sum_reduceIdEvPvS0_) + %1 = load double, ptr %0, align 8, !tbaa !5 + invoke void @_Z1hd(double noundef %1) + to label %invoke.cont unwind label %lpad + +invoke.cont: ; preds = %entry + %2 = call ptr @llvm.hyper.lookup.i64(ptr nonnull %sumAParRelError, i64 8, ptr nonnull @_Z8sum_initIdEvPv, ptr nonnull @_Z10sum_reduceIdEvPvS0_) + %3 = load double, ptr %2, align 8, !tbaa !5 + invoke void @_Z1hd(double noundef %3) + to label %invoke.cont1 unwind label %lpad + +invoke.cont1: ; preds = %invoke.cont + call void @llvm.reducer.unregister(ptr nonnull %sumAParRelError) + call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %sumAParRelError) #7 + ret void + +lpad: ; preds = %invoke.cont, %entry + %4 = landingpad { ptr, i32 } + cleanup + call void @llvm.reducer.unregister(ptr nonnull %sumAParRelError) + call void @llvm.lifetime.end.p0(i64 8, ptr nonnull %sumAParRelError) #7 + resume { ptr, i32 } %4 +} + +; Check insertion of __csan_llvm_hyper_lookup calls and use of their return values. + +; CHECK: define dso_local void @_Z3runv() + +; CHECK: %[[HYPER_LOOKUP:.+]] = call ptr @llvm.hyper.lookup.i64(ptr nonnull %sumAParRelError +; CHECK: %[[CSAN_HYPER_LOOKUP:.+]] = call {{.*}}ptr @__csan_llvm_hyper_lookup_i64(i64 %{{.*}}, i64 %{{.*}}, i8 3, i64 0, ptr %[[HYPER_LOOKUP]], +; CHECK: call void @__csan_load(i64 %{{.*}}, ptr %[[CSAN_HYPER_LOOKUP]], +; CHECK-NEXT: %[[VIEW_LOAD:.+]] = load double, ptr %[[CSAN_HYPER_LOOKUP]] + +; CHECK: invoke void @_Z1hd(double noundef %[[VIEW_LOAD]]) + +; CHECK: %[[HYPER_LOOKUP_2:.+]] = call ptr @llvm.hyper.lookup.i64(ptr nonnull %sumAParRelError +; CHECK: %[[CSAN_HYPER_LOOKUP_2:.+]] = call {{.*}}ptr @__csan_llvm_hyper_lookup_i64(i64 %{{.*}}, i64 %{{.*}}, i8 3, i64 0, ptr %[[HYPER_LOOKUP_2]], +; CHECK: call void @__csan_load(i64 %{{.*}}, ptr %[[CSAN_HYPER_LOOKUP_2]], +; CHECK-NEXT: %[[VIEW_LOAD_2:.+]] = load double, ptr %[[CSAN_HYPER_LOOKUP_2]] + +; CHECK: invoke void @_Z1hd(double noundef %[[VIEW_LOAD_2]]) + + +; Check that synthesized __csan_llvm_hyper_lookup function simply calls the default hook and returns the return-value parameter. + +; CHECK: define {{.*}}ptr @__csan_llvm_hyper_lookup_i64(i64 %0, i64 %1, i8 %2, i64 %3, ptr %4, ptr %5, i64 %6, ptr %7, ptr %8) +; CHECK-NEXT: entry: +; CHECK-NEXT: call {{.*}}void @__csan_default_libhook(i64 %0, i64 %1, i8 %2) +; CHECK-NEXT: ret ptr %4 +; CHECK-NEXT: } + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1 + +; Function Attrs: mustprogress nounwind sanitize_cilk uwtable +define linkonce_odr dso_local void @_Z8sum_initIdEvPv(ptr noundef %v) #2 comdat { +entry: + store double 0.000000e+00, ptr %v, align 8, !tbaa !5 + ret void +} + +; Function Attrs: mustprogress nounwind sanitize_cilk uwtable +define linkonce_odr dso_local void @_Z10sum_reduceIdEvPvS0_(ptr noundef %v, ptr noundef %v2) #2 comdat { +entry: + %0 = load double, ptr %v2, align 8, !tbaa !5 + %1 = load double, ptr %v, align 8, !tbaa !5 + %add = fadd double %0, %1 + store double %add, ptr %v, align 8, !tbaa !5 + ret void +} + +; Function Attrs: mustprogress nounwind reducer_register willreturn memory(inaccessiblemem: readwrite) +declare void @llvm.reducer.register.i64(ptr, i64, ptr, ptr) #3 + +declare i32 @__gxx_personality_v0(...) + +; Function Attrs: mustprogress nounwind reducer_unregister willreturn memory(inaccessiblemem: readwrite) +declare void @llvm.reducer.unregister(ptr) #4 + +; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) +declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1 + +declare void @_Z1hd(double noundef) local_unnamed_addr #5 + +; Function Attrs: hyper_view injective mustprogress nofree nounwind strand_pure willreturn memory(inaccessiblemem: read) +declare ptr @llvm.hyper.lookup.i64(ptr, i64, ptr, ptr) #6 + +attributes #0 = { mustprogress sanitize_cilk uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) } +attributes #2 = { mustprogress nounwind sanitize_cilk uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #3 = { mustprogress nounwind reducer_register willreturn memory(inaccessiblemem: readwrite) } +attributes #4 = { mustprogress nounwind reducer_unregister willreturn memory(inaccessiblemem: readwrite) } +attributes #5 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #6 = { hyper_view injective mustprogress nofree nounwind strand_pure willreturn memory(inaccessiblemem: read) } +attributes #7 = { nounwind } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{!"clang version 18.1.8 (git@github.com:neboat/opencilk-project.git c3cd84365e099ab6dfa4b484475ef66f33f16eab)"} +!5 = !{!6, !6, i64 0} +!6 = !{!"double", !7, i64 0} +!7 = !{!"omnipotent char", !8, i64 0} +!8 = !{!"Simple C++ TBAA"} diff --git a/llvm/test/Transforms/Tapir/CilkSanitizer/synthesize-alloc-hook.ll b/llvm/test/Transforms/Tapir/CilkSanitizer/synthesize-alloc-hook.ll new file mode 100644 index 000000000000..24cd640ffef9 --- /dev/null +++ b/llvm/test/Transforms/Tapir/CilkSanitizer/synthesize-alloc-hook.ll @@ -0,0 +1,40 @@ +; Check synthesis of alloc function hooks. +; +; RUN: opt < %s -passes="cilksan" -cilksan-bc-path=%S/null-bitcode.bc -S | FileCheck %s +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@.str = private unnamed_addr constant [2 x i8] c"a\00", align 1 + +; Function Attrs: mustprogress nofree nounwind sanitize_cilk willreturn memory(inaccessiblemem: readwrite) uwtable +define dso_local noalias noundef ptr @_Z8strdup_av() local_unnamed_addr #0 { +entry: + %call = tail call noalias dereferenceable_or_null(2) ptr @strdup(ptr noundef nonnull @.str) #2 + ret ptr %call +} + +; CHECK-LABEL: define dso_local noalias noundef ptr @_Z8strdup_av() +; CHECK: %[[CALL:.+]] = tail call noalias dereferenceable_or_null(2) ptr @strdup(ptr noundef nonnull @.str) +; CHECK-NEXT: call void @__csan_alloc_strdup(i64 %{{.*}}, i64 %{{.*}}, i8 0, i64 {{.*}}, ptr %[[CALL]], ptr @.str) +; CHECK: ret ptr %[[CALL]] + +; CHECK-LABEL: define void @__csan_alloc_strdup(i64 %0, i64 %1, i8 %2, i64 %3, ptr %4, ptr %5) +; CHECK-NEXT: entry: +; CHECK-NEXT: call void @__csan_default_libhook(i64 %0, i64 %1, i8 %2) +; CHECK-NEXT: ret void + +; Function Attrs: mustprogress nofree nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) +declare noalias ptr @strdup(ptr nocapture noundef readonly) local_unnamed_addr #1 + +attributes #0 = { mustprogress nofree nounwind sanitize_cilk willreturn memory(inaccessiblemem: readwrite) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #1 = { mustprogress nofree nounwind willreturn memory(argmem: readwrite, inaccessiblemem: readwrite) "alloc-family"="malloc" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0, !1, !2, !3} +!llvm.ident = !{!4} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 8, !"PIC Level", i32 2} +!2 = !{i32 7, !"PIE Level", i32 2} +!3 = !{i32 7, !"uwtable", i32 2} +!4 = !{!"clang version 18.1.8 (git@github.com:neboat/opencilk-project.git c3cd84365e099ab6dfa4b484475ef66f33f16eab)"}