diff --git a/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h b/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/ToUnreachable.h @@ -0,0 +1,22 @@ +//===- ToUnreachable.h - Turn function into unreachable. --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_TOUNREACHABLE_H +#define LLVM_TRANSFORMS_SCALAR_TOUNREACHABLE_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { +struct ToUnreachablePass : public PassInfoMixin { + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; +} // namespace llvm + +#endif diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -215,6 +215,7 @@ #include "llvm/Transforms/Scalar/StructurizeCFG.h" #include "llvm/Transforms/Scalar/TLSVariableHoist.h" #include "llvm/Transforms/Scalar/TailRecursionElimination.h" +#include "llvm/Transforms/Scalar/ToUnreachable.h" #include "llvm/Transforms/Scalar/WarnMissedTransforms.h" #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/AssumeBundleBuilder.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -381,6 +381,7 @@ FUNCTION_PASS("tlshoist", TLSVariableHoistPass()) FUNCTION_PASS("transform-warning", WarnMissedTransformationsPass()) FUNCTION_PASS("tsan", ThreadSanitizerPass()) +FUNCTION_PASS("to-unreachable", ToUnreachablePass()) FUNCTION_PASS("memprof", MemProfilerPass()) #undef FUNCTION_PASS diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt --- a/llvm/lib/Transforms/Scalar/CMakeLists.txt +++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -77,6 +77,7 @@ StructurizeCFG.cpp TailRecursionElimination.cpp TLSVariableHoist.cpp + ToUnreachable.cpp WarnMissedTransforms.cpp ADDITIONAL_HEADER_DIRS diff --git a/llvm/lib/Transforms/Scalar/ToUnreachable.cpp b/llvm/lib/Transforms/Scalar/ToUnreachable.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/ToUnreachable.cpp @@ -0,0 +1,36 @@ +//===- ToUnreachable.cpp - Turn function into unreachable. ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/ToUnreachable.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" + +using namespace llvm; + +PreservedAnalyses ToUnreachablePass::run(Function &F, + FunctionAnalysisManager &AM) { + SmallVector AllBlocks; + for (BasicBlock &BB : F) { + AllBlocks.push_back(&BB); + BB.dropAllReferences(); + } + + for (unsigned I = 1; I < AllBlocks.size(); ++I) { + AllBlocks[I]->eraseFromParent(); + } + + for (Instruction &I : make_early_inc_range(*AllBlocks[0])) { + I.eraseFromParent(); + } + + new UnreachableInst(F.getContext(), AllBlocks[0]); + return PreservedAnalyses::none(); +} diff --git a/llvm/utils/find-ub-in-test.sh b/llvm/utils/find-ub-in-test.sh new file mode 100755 --- /dev/null +++ b/llvm/utils/find-ub-in-test.sh @@ -0,0 +1,52 @@ +#!/bin/bash + +FILE="" +S_OPT="" +ORIG_ARGS="$@" +for arg in $@; do + shift + if [[ $arg == *".ll" ]]; then + FILE="${arg}" + fi +done + +if [[ "$OSTYPE" == "darwin"* ]]; then + # Mac + TV_SHAREDLIB=tv.dylib +else + # Linux, Cygwin/Msys, or Win32? + TV_SHAREDLIB=tv.so +fi + +TV_REPORT_DIR="" +TIMEOUT="" +TV_SMT_TO="" +TV_SMT_STATS="" +TV_REPORT_DIR=-tv-report-dir=alive2/build/logs +TIMEOUT="" +TV_SMT_TO="-tv-smt-to=100000" +TV_SMT_STATS=-tv-smt-stats + +NPM_PLUGIN="-load-pass-plugin=alive2/build/tv/$TV_SHAREDLIB" + +# Write input to temporary file so it can be passed to multiple opt calls, even +# if read from stdin. Run opt with original args, save output. +OUT=$(mktemp) +if [[ $FILE == "" ]]; then + FILE="$(mktemp)" + bin/opt > $FILE + bin/opt $ORIG_ARGS $FILE > $OUT +else + bin/opt $ORIG_ARGS > $OUT +fi + +# Check if replacing all input functions with unreachable still verifies. If it does, the input has likely unconditional UB. +bin/opt -load=live2/build/tv/$TV_SHAREDLIB $NPM_PLUGIN -tv-exit-on-error -passes="tv,to-unreachable,tv" -disable-output $FILE $TV_SMT_TO $TV_REPORT_DIR $TV_SMT_STATS 2> /dev/null +ret=$? + +cat $OUT + +if [ $ret -ne 0 ]; then + exit 0 +fi +exit 1