mirror of
https://github.com/opnsense/src.git
synced 2026-06-04 22:32:43 -04:00
Remove files from vendor/llvm-project/master which are unused, and never
merged to contrib.
This commit is contained in:
parent
c80d8fac37
commit
7cc9cf2bf0
50 changed files with 0 additions and 3682 deletions
|
|
@ -1,18 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS Support)
|
||||
|
||||
add_clang_library(clangTransformer
|
||||
RangeSelector.cpp
|
||||
RewriteRule.cpp
|
||||
SourceCode.cpp
|
||||
SourceCodeBuilders.cpp
|
||||
Stencil.cpp
|
||||
Transformer.cpp
|
||||
|
||||
LINK_LIBS
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangLex
|
||||
clangToolingCore
|
||||
clangToolingRefactoring
|
||||
)
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS BitWriter Core Support TransformUtils)
|
||||
|
||||
if(NOT CLANG_BUILT_STANDALONE)
|
||||
set(tablegen_deps intrinsics_gen)
|
||||
endif()
|
||||
|
||||
add_clang_tool(clang-offload-wrapper
|
||||
ClangOffloadWrapper.cpp
|
||||
|
||||
DEPENDS
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
||||
set(CLANG_OFFLOAD_WRAPPER_LIB_DEPS
|
||||
clangBasic
|
||||
)
|
||||
|
||||
add_dependencies(clang clang-offload-wrapper)
|
||||
|
||||
clang_target_link_libraries(clang-offload-wrapper
|
||||
PRIVATE
|
||||
${CLANG_OFFLOAD_WRAPPER_LIB_DEPS}
|
||||
)
|
||||
|
|
@ -1,371 +0,0 @@
|
|||
//===-- clang-offload-wrapper/ClangOffloadWrapper.cpp -----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Implementation of the offload wrapper tool. It takes offload target binaries
|
||||
/// as input and creates wrapper bitcode file containing target binaries
|
||||
/// packaged as data. Wrapper bitcode also includes initialization code which
|
||||
/// registers target binaries in offloading runtime at program startup.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "clang/Basic/Version.h"
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Bitcode/BitcodeWriter.h"
|
||||
#include "llvm/IR/Constants.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/ErrorOr.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/Utils/ModuleUtils.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
||||
|
||||
// Mark all our options with this category, everything else (except for -version
|
||||
// and -help) will be hidden.
|
||||
static cl::OptionCategory
|
||||
ClangOffloadWrapperCategory("clang-offload-wrapper options");
|
||||
|
||||
static cl::opt<std::string> Output("o", cl::Required,
|
||||
cl::desc("Output filename"),
|
||||
cl::value_desc("filename"),
|
||||
cl::cat(ClangOffloadWrapperCategory));
|
||||
|
||||
static cl::list<std::string> Inputs(cl::Positional, cl::OneOrMore,
|
||||
cl::desc("<input files>"),
|
||||
cl::cat(ClangOffloadWrapperCategory));
|
||||
|
||||
static cl::opt<std::string>
|
||||
Target("target", cl::Required,
|
||||
cl::desc("Target triple for the output module"),
|
||||
cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory));
|
||||
|
||||
namespace {
|
||||
|
||||
class BinaryWrapper {
|
||||
LLVMContext C;
|
||||
Module M;
|
||||
|
||||
StructType *EntryTy = nullptr;
|
||||
StructType *ImageTy = nullptr;
|
||||
StructType *DescTy = nullptr;
|
||||
|
||||
private:
|
||||
IntegerType *getSizeTTy() {
|
||||
switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) {
|
||||
case 4u:
|
||||
return Type::getInt32Ty(C);
|
||||
case 8u:
|
||||
return Type::getInt64Ty(C);
|
||||
}
|
||||
llvm_unreachable("unsupported pointer type size");
|
||||
}
|
||||
|
||||
// struct __tgt_offload_entry {
|
||||
// void *addr;
|
||||
// char *name;
|
||||
// size_t size;
|
||||
// int32_t flags;
|
||||
// int32_t reserved;
|
||||
// };
|
||||
StructType *getEntryTy() {
|
||||
if (!EntryTy)
|
||||
EntryTy = StructType::create("__tgt_offload_entry", Type::getInt8PtrTy(C),
|
||||
Type::getInt8PtrTy(C), getSizeTTy(),
|
||||
Type::getInt32Ty(C), Type::getInt32Ty(C));
|
||||
return EntryTy;
|
||||
}
|
||||
|
||||
PointerType *getEntryPtrTy() { return PointerType::getUnqual(getEntryTy()); }
|
||||
|
||||
// struct __tgt_device_image {
|
||||
// void *ImageStart;
|
||||
// void *ImageEnd;
|
||||
// __tgt_offload_entry *EntriesBegin;
|
||||
// __tgt_offload_entry *EntriesEnd;
|
||||
// };
|
||||
StructType *getDeviceImageTy() {
|
||||
if (!ImageTy)
|
||||
ImageTy = StructType::create("__tgt_device_image", Type::getInt8PtrTy(C),
|
||||
Type::getInt8PtrTy(C), getEntryPtrTy(),
|
||||
getEntryPtrTy());
|
||||
return ImageTy;
|
||||
}
|
||||
|
||||
PointerType *getDeviceImagePtrTy() {
|
||||
return PointerType::getUnqual(getDeviceImageTy());
|
||||
}
|
||||
|
||||
// struct __tgt_bin_desc {
|
||||
// int32_t NumDeviceImages;
|
||||
// __tgt_device_image *DeviceImages;
|
||||
// __tgt_offload_entry *HostEntriesBegin;
|
||||
// __tgt_offload_entry *HostEntriesEnd;
|
||||
// };
|
||||
StructType *getBinDescTy() {
|
||||
if (!DescTy)
|
||||
DescTy = StructType::create("__tgt_bin_desc", Type::getInt32Ty(C),
|
||||
getDeviceImagePtrTy(), getEntryPtrTy(),
|
||||
getEntryPtrTy());
|
||||
return DescTy;
|
||||
}
|
||||
|
||||
PointerType *getBinDescPtrTy() {
|
||||
return PointerType::getUnqual(getBinDescTy());
|
||||
}
|
||||
|
||||
/// Creates binary descriptor for the given device images. Binary descriptor
|
||||
/// is an object that is passed to the offloading runtime at program startup
|
||||
/// and it describes all device images available in the executable or shared
|
||||
/// library. It is defined as follows
|
||||
///
|
||||
/// __attribute__((visibility("hidden")))
|
||||
/// extern __tgt_offload_entry *__start_omp_offloading_entries;
|
||||
/// __attribute__((visibility("hidden")))
|
||||
/// extern __tgt_offload_entry *__stop_omp_offloading_entries;
|
||||
///
|
||||
/// static const char Image0[] = { <Bufs.front() contents> };
|
||||
/// ...
|
||||
/// static const char ImageN[] = { <Bufs.back() contents> };
|
||||
///
|
||||
/// static const __tgt_device_image Images[] = {
|
||||
/// {
|
||||
/// Image0, /*ImageStart*/
|
||||
/// Image0 + sizeof(Image0), /*ImageEnd*/
|
||||
/// __start_omp_offloading_entries, /*EntriesBegin*/
|
||||
/// __stop_omp_offloading_entries /*EntriesEnd*/
|
||||
/// },
|
||||
/// ...
|
||||
/// {
|
||||
/// ImageN, /*ImageStart*/
|
||||
/// ImageN + sizeof(ImageN), /*ImageEnd*/
|
||||
/// __start_omp_offloading_entries, /*EntriesBegin*/
|
||||
/// __stop_omp_offloading_entries /*EntriesEnd*/
|
||||
/// }
|
||||
/// };
|
||||
///
|
||||
/// static const __tgt_bin_desc BinDesc = {
|
||||
/// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/
|
||||
/// Images, /*DeviceImages*/
|
||||
/// __start_omp_offloading_entries, /*HostEntriesBegin*/
|
||||
/// __stop_omp_offloading_entries /*HostEntriesEnd*/
|
||||
/// };
|
||||
///
|
||||
/// Global variable that represents BinDesc is returned.
|
||||
GlobalVariable *createBinDesc(ArrayRef<ArrayRef<char>> Bufs) {
|
||||
// Create external begin/end symbols for the offload entries table.
|
||||
auto *EntriesB = new GlobalVariable(
|
||||
M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
|
||||
/*Initializer*/ nullptr, "__start_omp_offloading_entries");
|
||||
EntriesB->setVisibility(GlobalValue::HiddenVisibility);
|
||||
auto *EntriesE = new GlobalVariable(
|
||||
M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
|
||||
/*Initializer*/ nullptr, "__stop_omp_offloading_entries");
|
||||
EntriesE->setVisibility(GlobalValue::HiddenVisibility);
|
||||
|
||||
// We assume that external begin/end symbols that we have created above will
|
||||
// be defined by the linker. But linker will do that only if linker inputs
|
||||
// have section with "omp_offloading_entries" name which is not guaranteed.
|
||||
// So, we just create dummy zero sized object in the offload entries section
|
||||
// to force linker to define those symbols.
|
||||
auto *DummyInit =
|
||||
ConstantAggregateZero::get(ArrayType::get(getEntryTy(), 0u));
|
||||
auto *DummyEntry = new GlobalVariable(
|
||||
M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage,
|
||||
DummyInit, "__dummy.omp_offloading.entry");
|
||||
DummyEntry->setSection("omp_offloading_entries");
|
||||
DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
|
||||
|
||||
auto *Zero = ConstantInt::get(getSizeTTy(), 0u);
|
||||
Constant *ZeroZero[] = {Zero, Zero};
|
||||
|
||||
// Create initializer for the images array.
|
||||
SmallVector<Constant *, 4u> ImagesInits;
|
||||
ImagesInits.reserve(Bufs.size());
|
||||
for (ArrayRef<char> Buf : Bufs) {
|
||||
auto *Data = ConstantDataArray::get(C, Buf);
|
||||
auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
|
||||
GlobalVariable::InternalLinkage, Data,
|
||||
".omp_offloading.device_image");
|
||||
Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
auto *Size = ConstantInt::get(getSizeTTy(), Buf.size());
|
||||
Constant *ZeroSize[] = {Zero, Size};
|
||||
|
||||
auto *ImageB = ConstantExpr::getGetElementPtr(Image->getValueType(),
|
||||
Image, ZeroZero);
|
||||
auto *ImageE = ConstantExpr::getGetElementPtr(Image->getValueType(),
|
||||
Image, ZeroSize);
|
||||
|
||||
ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(), ImageB,
|
||||
ImageE, EntriesB, EntriesE));
|
||||
}
|
||||
|
||||
// Then create images array.
|
||||
auto *ImagesData = ConstantArray::get(
|
||||
ArrayType::get(getDeviceImageTy(), ImagesInits.size()), ImagesInits);
|
||||
|
||||
auto *Images =
|
||||
new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, ImagesData,
|
||||
".omp_offloading.device_images");
|
||||
Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||||
|
||||
auto *ImagesB = ConstantExpr::getGetElementPtr(Images->getValueType(),
|
||||
Images, ZeroZero);
|
||||
|
||||
// And finally create the binary descriptor object.
|
||||
auto *DescInit = ConstantStruct::get(
|
||||
getBinDescTy(),
|
||||
ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB,
|
||||
EntriesB, EntriesE);
|
||||
|
||||
return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
|
||||
GlobalValue::InternalLinkage, DescInit,
|
||||
".omp_offloading.descriptor");
|
||||
}
|
||||
|
||||
void createRegisterFunction(GlobalVariable *BinDesc) {
|
||||
auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
".omp_offloading.descriptor_reg", &M);
|
||||
Func->setSection(".text.startup");
|
||||
|
||||
// Get __tgt_register_lib function declaration.
|
||||
auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
|
||||
/*isVarArg*/ false);
|
||||
FunctionCallee RegFuncC =
|
||||
M.getOrInsertFunction("__tgt_register_lib", RegFuncTy);
|
||||
|
||||
// Construct function body
|
||||
IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
|
||||
Builder.CreateCall(RegFuncC, BinDesc);
|
||||
Builder.CreateRetVoid();
|
||||
|
||||
// Add this function to constructors.
|
||||
appendToGlobalCtors(M, Func, 0);
|
||||
}
|
||||
|
||||
void createUnregisterFunction(GlobalVariable *BinDesc) {
|
||||
auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
|
||||
auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
|
||||
".omp_offloading.descriptor_unreg", &M);
|
||||
Func->setSection(".text.startup");
|
||||
|
||||
// Get __tgt_unregister_lib function declaration.
|
||||
auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
|
||||
/*isVarArg*/ false);
|
||||
FunctionCallee UnRegFuncC =
|
||||
M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy);
|
||||
|
||||
// Construct function body
|
||||
IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
|
||||
Builder.CreateCall(UnRegFuncC, BinDesc);
|
||||
Builder.CreateRetVoid();
|
||||
|
||||
// Add this function to global destructors.
|
||||
appendToGlobalDtors(M, Func, 0);
|
||||
}
|
||||
|
||||
public:
|
||||
BinaryWrapper(StringRef Target) : M("offload.wrapper.object", C) {
|
||||
M.setTargetTriple(Target);
|
||||
}
|
||||
|
||||
const Module &wrapBinaries(ArrayRef<ArrayRef<char>> Binaries) {
|
||||
GlobalVariable *Desc = createBinDesc(Binaries);
|
||||
assert(Desc && "no binary descriptor");
|
||||
createRegisterFunction(Desc);
|
||||
createUnregisterFunction(Desc);
|
||||
return M;
|
||||
}
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
sys::PrintStackTraceOnErrorSignal(argv[0]);
|
||||
|
||||
cl::HideUnrelatedOptions(ClangOffloadWrapperCategory);
|
||||
cl::SetVersionPrinter([](raw_ostream &OS) {
|
||||
OS << clang::getClangToolFullVersion("clang-offload-wrapper") << '\n';
|
||||
});
|
||||
cl::ParseCommandLineOptions(
|
||||
argc, argv,
|
||||
"A tool to create a wrapper bitcode for offload target binaries. Takes "
|
||||
"offload\ntarget binaries as input and produces bitcode file containing "
|
||||
"target binaries packaged\nas data and initialization code which "
|
||||
"registers target binaries in offload runtime.\n");
|
||||
|
||||
if (Help) {
|
||||
cl::PrintHelpMessage();
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto reportError = [argv](Error E) {
|
||||
logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
|
||||
};
|
||||
|
||||
if (Triple(Target).getArch() == Triple::UnknownArch) {
|
||||
reportError(createStringError(
|
||||
errc::invalid_argument, "'" + Target + "': unsupported target triple"));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Read device binaries.
|
||||
SmallVector<std::unique_ptr<MemoryBuffer>, 4u> Buffers;
|
||||
SmallVector<ArrayRef<char>, 4u> Images;
|
||||
Buffers.reserve(Inputs.size());
|
||||
Images.reserve(Inputs.size());
|
||||
for (const std::string &File : Inputs) {
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
|
||||
MemoryBuffer::getFileOrSTDIN(File);
|
||||
if (!BufOrErr) {
|
||||
reportError(createFileError(File, BufOrErr.getError()));
|
||||
return 1;
|
||||
}
|
||||
const std::unique_ptr<MemoryBuffer> &Buf =
|
||||
Buffers.emplace_back(std::move(*BufOrErr));
|
||||
Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize());
|
||||
}
|
||||
|
||||
// Create the output file to write the resulting bitcode to.
|
||||
std::error_code EC;
|
||||
ToolOutputFile Out(Output, EC, sys::fs::OF_None);
|
||||
if (EC) {
|
||||
reportError(createFileError(Output, EC));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create a wrapper for device binaries and write its bitcode to the file.
|
||||
WriteBitcodeToFile(BinaryWrapper(Target).wrapBinaries(
|
||||
makeArrayRef(Images.data(), Images.size())),
|
||||
Out.os());
|
||||
if (Out.os().has_error()) {
|
||||
reportError(createFileError(Output, Out.os().error()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Success.
|
||||
Out.keep();
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,55 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
# The lines that we're looking to symbolize look like this:
|
||||
#0 ./a.out(_foo+0x3e6) [0x55a52e64c696]
|
||||
# ... which come from the backtrace_symbols() symbolisation function used by
|
||||
# default in Scudo's implementation of GWP-ASan.
|
||||
|
||||
while read -r line; do
|
||||
# Check that this line needs symbolization.
|
||||
should_symbolize="$(echo $line |\
|
||||
grep -E '^[ ]*\#.*\(.*\+0x[0-9a-f]+\) \[0x[0-9a-f]+\]$')"
|
||||
|
||||
if [ -z "$should_symbolize" ]; then
|
||||
echo "$line"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Carve up the input line into sections.
|
||||
binary_name="$(echo $line | grep -oE ' .*\(' | rev | cut -c2- | rev |\
|
||||
cut -c2-)"
|
||||
function_name="$(echo $line | grep -oE '\([^+]*' | cut -c2-)"
|
||||
function_offset="$(echo $line | grep -oE '\(.*\)' | grep -oE '\+.*\)' |\
|
||||
cut -c2- | rev | cut -c2- | rev)"
|
||||
frame_number="$(echo $line | grep -oE '\#[0-9]+ ')"
|
||||
|
||||
if [ -z "$function_name" ]; then
|
||||
# If the offset is binary-relative, just resolve that.
|
||||
symbolized="$(echo $function_offset | addr2line -e $binary_name)"
|
||||
else
|
||||
# Otherwise, the offset is function-relative. Get the address of the
|
||||
# function, and add it to the offset, then symbolize.
|
||||
function_addr="0x$(echo $function_offset |\
|
||||
nm --defined-only $binary_name 2> /dev/null |\
|
||||
grep -E " $function_name$" | cut -d' ' -f1)"
|
||||
|
||||
# Check that we could get the function address from nm.
|
||||
if [ -z "$function_addr" ]; then
|
||||
echo "$line"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Add the function address and offset to get the offset into the binary.
|
||||
binary_offset="$(printf "0x%X" "$((function_addr+function_offset))")"
|
||||
symbolized="$(echo $binary_offset | addr2line -e $binary_name)"
|
||||
fi
|
||||
|
||||
# Check that it symbolized properly. If it didn't, output the old line.
|
||||
echo $symbolized | grep -E ".*\?.*:" > /dev/null
|
||||
if [ "$?" -eq "0" ]; then
|
||||
echo "$line"
|
||||
continue
|
||||
else
|
||||
echo "${frame_number}${symbolized}"
|
||||
fi
|
||||
done
|
||||
|
|
@ -1 +0,0 @@
|
|||
add_subdirectory(gwp_asan)
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# Build the stack trace compressor fuzzer. This will require Clang >= 6.0.0, as
|
||||
# -fsanitize=fuzzer-no-link was not a valid command line flag prior to this.
|
||||
if (LLVM_USE_SANITIZE_COVERAGE)
|
||||
add_executable(stack_trace_compressor_fuzzer
|
||||
../../lib/gwp_asan/stack_trace_compressor.cpp
|
||||
../../lib/gwp_asan/stack_trace_compressor.h
|
||||
stack_trace_compressor_fuzzer.cpp)
|
||||
set_target_properties(
|
||||
stack_trace_compressor_fuzzer PROPERTIES FOLDER "Fuzzers")
|
||||
target_compile_options(
|
||||
stack_trace_compressor_fuzzer PRIVATE -fsanitize=fuzzer-no-link)
|
||||
set_target_properties(
|
||||
stack_trace_compressor_fuzzer PROPERTIES LINK_FLAGS -fsanitize=fuzzer)
|
||||
target_include_directories(
|
||||
stack_trace_compressor_fuzzer PRIVATE ../../lib/)
|
||||
|
||||
if (TARGET gwp_asan)
|
||||
add_dependencies(gwp_asan stack_trace_compressor_fuzzer)
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
#include "gwp_asan/stack_trace_compressor.h"
|
||||
|
||||
constexpr size_t kBytesForLargestVarInt = (sizeof(uintptr_t) * 8) / 7 + 1;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
size_t BufferSize = kBytesForLargestVarInt * Size / sizeof(uintptr_t);
|
||||
std::vector<uint8_t> Buffer(BufferSize);
|
||||
std::vector<uint8_t> Buffer2(BufferSize);
|
||||
|
||||
// Unpack the fuzz bytes.
|
||||
gwp_asan::compression::unpack(Data, Size,
|
||||
reinterpret_cast<uintptr_t *>(Buffer2.data()),
|
||||
BufferSize / sizeof(uintptr_t));
|
||||
|
||||
// Pack the fuzz bytes.
|
||||
size_t BytesWritten = gwp_asan::compression::pack(
|
||||
reinterpret_cast<const uintptr_t *>(Data), Size / sizeof(uintptr_t),
|
||||
Buffer.data(), BufferSize);
|
||||
|
||||
// Unpack the compressed buffer.
|
||||
size_t DecodedElements = gwp_asan::compression::unpack(
|
||||
Buffer.data(), BytesWritten,
|
||||
reinterpret_cast<uintptr_t *>(Buffer2.data()),
|
||||
BufferSize / sizeof(uintptr_t));
|
||||
|
||||
// Ensure that every element was encoded and decoded properly.
|
||||
if (DecodedElements != Size / sizeof(uintptr_t))
|
||||
abort();
|
||||
|
||||
// Ensure that the compression and uncompression resulted in the same trace.
|
||||
const uintptr_t *FuzzPtrs = reinterpret_cast<const uintptr_t *>(Data);
|
||||
const uintptr_t *DecodedPtrs =
|
||||
reinterpret_cast<const uintptr_t *>(Buffer2.data());
|
||||
for (size_t i = 0; i < Size / sizeof(uintptr_t); ++i) {
|
||||
if (FuzzPtrs[i] != DecodedPtrs[i]) {
|
||||
fprintf(stderr, "FuzzPtrs[%zu] != DecodedPtrs[%zu] (0x%zx vs. 0x%zx)", i,
|
||||
i, FuzzPtrs[i], DecodedPtrs[i]);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,399 +0,0 @@
|
|||
set(LIBCXX_LIB_CMAKEFILES_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}" PARENT_SCOPE)
|
||||
|
||||
# Get sources
|
||||
set(LIBCXX_SOURCES
|
||||
algorithm.cpp
|
||||
any.cpp
|
||||
bind.cpp
|
||||
charconv.cpp
|
||||
chrono.cpp
|
||||
condition_variable.cpp
|
||||
condition_variable_destructor.cpp
|
||||
debug.cpp
|
||||
exception.cpp
|
||||
functional.cpp
|
||||
future.cpp
|
||||
hash.cpp
|
||||
include/apple_availability.h
|
||||
include/atomic_support.h
|
||||
include/config_elast.h
|
||||
include/refstring.h
|
||||
ios.cpp
|
||||
iostream.cpp
|
||||
locale.cpp
|
||||
memory.cpp
|
||||
mutex.cpp
|
||||
mutex_destructor.cpp
|
||||
new.cpp
|
||||
optional.cpp
|
||||
random.cpp
|
||||
regex.cpp
|
||||
shared_mutex.cpp
|
||||
stdexcept.cpp
|
||||
string.cpp
|
||||
strstream.cpp
|
||||
support/runtime/exception_fallback.ipp
|
||||
support/runtime/exception_glibcxx.ipp
|
||||
support/runtime/exception_libcxxabi.ipp
|
||||
support/runtime/exception_libcxxrt.ipp
|
||||
support/runtime/exception_msvc.ipp
|
||||
support/runtime/exception_pointer_cxxabi.ipp
|
||||
support/runtime/exception_pointer_glibcxx.ipp
|
||||
support/runtime/exception_pointer_msvc.ipp
|
||||
support/runtime/exception_pointer_unimplemented.ipp
|
||||
support/runtime/new_handler_fallback.ipp
|
||||
support/runtime/stdexcept_default.ipp
|
||||
support/runtime/stdexcept_vcruntime.ipp
|
||||
system_error.cpp
|
||||
thread.cpp
|
||||
typeinfo.cpp
|
||||
utility.cpp
|
||||
valarray.cpp
|
||||
variant.cpp
|
||||
vector.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
support/win32/locale_win32.cpp
|
||||
support/win32/support.cpp
|
||||
support/win32/thread_win32.cpp
|
||||
)
|
||||
elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
support/solaris/mbsnrtowcs.inc
|
||||
support/solaris/wcsnrtombs.inc
|
||||
support/solaris/xlocale.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ENABLE_FILESYSTEM)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
filesystem/filesystem_common.h
|
||||
filesystem/operations.cpp
|
||||
filesystem/directory_iterator.cpp
|
||||
)
|
||||
# Filesystem uses __int128_t, which requires a definition of __muloi4 when
|
||||
# compiled with UBSAN. This definition is not provided by libgcc_s, but is
|
||||
# provided by compiler-rt. So we need to disable it to avoid having multiple
|
||||
# definitions. See filesystem/int128_builtins.cpp.
|
||||
if (NOT LIBCXX_USE_COMPILER_RT)
|
||||
list(APPEND LIBCXX_SOURCES
|
||||
filesystem/int128_builtins.cpp
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add all the headers to the project for IDEs.
|
||||
if (LIBCXX_CONFIGURE_IDE)
|
||||
file(GLOB_RECURSE LIBCXX_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/*)
|
||||
if(WIN32)
|
||||
file( GLOB LIBCXX_WIN32_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/../include/support/win32/*.h)
|
||||
list(APPEND LIBCXX_HEADERS ${LIBCXX_WIN32_HEADERS})
|
||||
endif()
|
||||
# Force them all into the headers dir on MSVC, otherwise they end up at
|
||||
# project scope because they don't have extensions.
|
||||
if (MSVC_IDE)
|
||||
source_group("Header Files" FILES ${LIBCXX_HEADERS})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT LIBCXX_INSTALL_LIBRARY)
|
||||
set(exclude_from_all EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# If LIBCXX_CXX_ABI_LIBRARY_PATH is defined we want to add it to the search path.
|
||||
add_link_flags_if(LIBCXX_CXX_ABI_LIBRARY_PATH
|
||||
"${CMAKE_LIBRARY_PATH_FLAG}${LIBCXX_CXX_ABI_LIBRARY_PATH}")
|
||||
|
||||
|
||||
if (LIBCXX_GENERATE_COVERAGE AND NOT LIBCXX_COVERAGE_LIBRARY)
|
||||
find_compiler_rt_library(profile LIBCXX_COVERAGE_LIBRARY)
|
||||
endif()
|
||||
add_library_flags_if(LIBCXX_COVERAGE_LIBRARY "${LIBCXX_COVERAGE_LIBRARY}")
|
||||
|
||||
if (APPLE AND LLVM_USE_SANITIZER)
|
||||
if (("${LLVM_USE_SANITIZER}" STREQUAL "Address") OR
|
||||
("${LLVM_USE_SANITIZER}" STREQUAL "Address;Undefined") OR
|
||||
("${LLVM_USE_SANITIZER}" STREQUAL "Undefined;Address"))
|
||||
set(LIBFILE "libclang_rt.asan_osx_dynamic.dylib")
|
||||
elseif("${LLVM_USE_SANITIZER}" STREQUAL "Undefined")
|
||||
set(LIBFILE "libclang_rt.ubsan_osx_dynamic.dylib")
|
||||
elseif("${LLVM_USE_SANITIZER}" STREQUAL "Thread")
|
||||
set(LIBFILE "libclang_rt.tsan_osx_dynamic.dylib")
|
||||
else()
|
||||
message(WARNING "LLVM_USE_SANITIZER=${LLVM_USE_SANITIZER} is not supported on OS X")
|
||||
endif()
|
||||
if (LIBFILE)
|
||||
find_compiler_rt_dir(LIBDIR)
|
||||
if (NOT IS_DIRECTORY "${LIBDIR}")
|
||||
message(FATAL_ERROR "Cannot find compiler-rt directory on OS X required for LLVM_USE_SANITIZER")
|
||||
endif()
|
||||
set(LIBCXX_SANITIZER_LIBRARY "${LIBDIR}/${LIBFILE}")
|
||||
set(LIBCXX_SANITIZER_LIBRARY "${LIBCXX_SANITIZER_LIBRARY}" PARENT_SCOPE)
|
||||
message(STATUS "Manually linking compiler-rt library: ${LIBCXX_SANITIZER_LIBRARY}")
|
||||
add_library_flags("${LIBCXX_SANITIZER_LIBRARY}")
|
||||
add_link_flags("-Wl,-rpath,${LIBDIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ENABLE_PARALLEL_ALGORITHMS AND NOT TARGET pstl::ParallelSTL)
|
||||
message(FATAL_ERROR "Could not find ParallelSTL")
|
||||
endif()
|
||||
|
||||
function(cxx_set_common_defines name)
|
||||
if(LIBCXX_CXX_ABI_HEADER_TARGET)
|
||||
add_dependencies(${name} ${LIBCXX_CXX_ABI_HEADER_TARGET})
|
||||
endif()
|
||||
|
||||
if (LIBCXX_ENABLE_PARALLEL_ALGORITHMS)
|
||||
target_link_libraries(${name} PUBLIC pstl::ParallelSTL)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
split_list(LIBCXX_COMPILE_FLAGS)
|
||||
split_list(LIBCXX_LINK_FLAGS)
|
||||
|
||||
# Build the shared library.
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
add_library(cxx_shared SHARED ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
|
||||
if(COMMAND llvm_setup_rpath)
|
||||
llvm_setup_rpath(cxx_shared)
|
||||
endif()
|
||||
target_link_libraries(cxx_shared PRIVATE ${LIBCXX_LIBRARIES})
|
||||
set_target_properties(cxx_shared
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}"
|
||||
LINK_FLAGS "${LIBCXX_LINK_FLAGS}"
|
||||
OUTPUT_NAME "c++"
|
||||
VERSION "${LIBCXX_ABI_VERSION}.0"
|
||||
SOVERSION "${LIBCXX_ABI_VERSION}"
|
||||
DEFINE_SYMBOL ""
|
||||
)
|
||||
cxx_add_common_build_flags(cxx_shared)
|
||||
cxx_set_common_defines(cxx_shared)
|
||||
|
||||
# Link against LLVM libunwind
|
||||
if (LIBCXXABI_USE_LLVM_UNWINDER)
|
||||
if (NOT LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_shared OR HAVE_LIBUNWIND))
|
||||
target_link_libraries(cxx_shared PUBLIC unwind_shared)
|
||||
elseif (LIBCXXABI_STATICALLY_LINK_UNWINDER_IN_SHARED_LIBRARY AND (TARGET unwind_static OR HAVE_LIBUNWIND))
|
||||
# libunwind is already included in libc++abi
|
||||
else()
|
||||
target_link_libraries(cxx_shared PUBLIC unwind)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Link against libc++abi
|
||||
if (LIBCXX_STATICALLY_LINK_ABI_IN_SHARED_LIBRARY)
|
||||
if (APPLE)
|
||||
target_link_libraries(cxx_shared PRIVATE "-Wl,-force_load" "${LIBCXX_CXX_STATIC_ABI_LIBRARY}")
|
||||
else()
|
||||
target_link_libraries(cxx_shared PRIVATE "-Wl,--whole-archive,-Bstatic" "${LIBCXX_CXX_STATIC_ABI_LIBRARY}" "-Wl,-Bdynamic,--no-whole-archive")
|
||||
endif()
|
||||
else()
|
||||
target_link_libraries(cxx_shared PUBLIC "${LIBCXX_CXX_SHARED_ABI_LIBRARY}")
|
||||
endif()
|
||||
|
||||
# Maybe re-export symbols from libc++abi
|
||||
if (APPLE AND (LIBCXX_CXX_ABI_LIBNAME STREQUAL "libcxxabi" OR
|
||||
LIBCXX_CXX_ABI_LIBNAME STREQUAL "default")
|
||||
AND NOT DEFINED LIBCXX_OSX_REEXPORT_LIBCXXABI_SYMBOLS)
|
||||
set(LIBCXX_OSX_REEXPORT_LIBCXXABI_SYMBOLS ON)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_OSX_REEXPORT_LIBCXXABI_SYMBOLS)
|
||||
if ("${CMAKE_OSX_ARCHITECTURES}" MATCHES "^(armv6|armv7|armv7s)$")
|
||||
set(RE_EXPORT_LIST "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libc++sjlj-abi.v${LIBCXX_LIBCPPABI_VERSION}.exp")
|
||||
else()
|
||||
set(RE_EXPORT_LIST "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libc++abi.v${LIBCXX_LIBCPPABI_VERSION}.exp")
|
||||
endif()
|
||||
target_link_libraries(cxx_shared PRIVATE
|
||||
"-Wl,-unexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/libc++unexp.exp"
|
||||
"-Wl,-reexported_symbols_list,${RE_EXPORT_LIST}"
|
||||
"-Wl,-force_symbols_not_weak_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/notweak.exp"
|
||||
"-Wl,-force_symbols_weak_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/weak.exp")
|
||||
|
||||
if (NOT LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS)
|
||||
target_link_libraries(cxx_shared PRIVATE "-Wl,-reexported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/../lib/libc++abi-new-delete.exp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Generate a linker script in place of a libc++.so symlink.
|
||||
if (LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
|
||||
include(DefineLinkerScript)
|
||||
define_linker_script(cxx_shared)
|
||||
endif()
|
||||
|
||||
list(APPEND LIBCXX_BUILD_TARGETS "cxx_shared")
|
||||
if(WIN32 AND NOT MINGW AND NOT "${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
# Since we most likely do not have a mt.exe replacement, disable the
|
||||
# manifest bundling. This allows a normal cmake invocation to pass which
|
||||
# will attempt to use the manifest tool to generate the bundled manifest
|
||||
set_target_properties(cxx_shared PROPERTIES
|
||||
APPEND_STRING PROPERTY LINK_FLAGS " /MANIFEST:NO")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build the static library.
|
||||
if (LIBCXX_ENABLE_STATIC)
|
||||
add_library(cxx_static STATIC ${exclude_from_all} ${LIBCXX_SOURCES} ${LIBCXX_HEADERS})
|
||||
target_link_libraries(cxx_static PRIVATE ${LIBCXX_LIBRARIES})
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
|
||||
set_target_properties(cxx_static
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}"
|
||||
LINK_FLAGS "${LIBCXX_LINK_FLAGS}"
|
||||
OUTPUT_NAME "c++"
|
||||
)
|
||||
cxx_add_common_build_flags(cxx_static)
|
||||
cxx_set_common_defines(cxx_static)
|
||||
|
||||
if (LIBCXX_HERMETIC_STATIC_LIBRARY)
|
||||
# If the hermetic library doesn't define the operator new/delete functions
|
||||
# then its code shouldn't declare them with hidden visibility. They might
|
||||
# actually be provided by a shared library at link time.
|
||||
if (LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS)
|
||||
append_flags_if_supported(CXX_STATIC_LIBRARY_FLAGS -fvisibility-global-new-delete-hidden)
|
||||
endif()
|
||||
target_compile_options(cxx_static PRIVATE ${CXX_STATIC_LIBRARY_FLAGS})
|
||||
target_compile_definitions(cxx_static PRIVATE _LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS)
|
||||
endif()
|
||||
|
||||
list(APPEND LIBCXX_BUILD_TARGETS "cxx_static")
|
||||
# Attempt to merge the libc++.a archive and the ABI library archive into one.
|
||||
if (LIBCXX_STATICALLY_LINK_ABI_IN_STATIC_LIBRARY)
|
||||
set(MERGE_ARCHIVES_SEARCH_PATHS "")
|
||||
if (LIBCXX_CXX_ABI_LIBRARY_PATH)
|
||||
set(MERGE_ARCHIVES_SEARCH_PATHS "-L${LIBCXX_CXX_ABI_LIBRARY_PATH}")
|
||||
endif()
|
||||
if (TARGET "${LIBCXX_CXX_STATIC_ABI_LIBRARY}" OR HAVE_LIBCXXABI)
|
||||
set(MERGE_ARCHIVES_ABI_TARGET "$<TARGET_LINKER_FILE:${LIBCXX_CXX_STATIC_ABI_LIBRARY}>")
|
||||
else()
|
||||
set(MERGE_ARCHIVES_ABI_TARGET
|
||||
"${CMAKE_STATIC_LIBRARY_PREFIX}${LIBCXX_CXX_STATIC_ABI_LIBRARY}${CMAKE_STATIC_LIBRARY_SUFFIX}")
|
||||
endif()
|
||||
if (APPLE)
|
||||
set(MERGE_ARCHIVES_LIBTOOL "--use-libtool" "--libtool" "${CMAKE_LIBTOOL}")
|
||||
endif()
|
||||
add_custom_command(TARGET cxx_static POST_BUILD
|
||||
COMMAND
|
||||
${PYTHON_EXECUTABLE} ${LIBCXX_SOURCE_DIR}/utils/merge_archives.py
|
||||
ARGS
|
||||
-o $<TARGET_LINKER_FILE:cxx_static>
|
||||
--ar "${CMAKE_AR}"
|
||||
${MERGE_ARCHIVES_LIBTOOL}
|
||||
"$<TARGET_LINKER_FILE:cxx_static>"
|
||||
"${MERGE_ARCHIVES_ABI_TARGET}"
|
||||
"${MERGE_ARCHIVES_SEARCH_PATHS}"
|
||||
WORKING_DIRECTORY ${LIBCXX_BUILD_DIR}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Add a meta-target for both libraries.
|
||||
add_custom_target(cxx DEPENDS cxx-headers ${LIBCXX_BUILD_TARGETS})
|
||||
|
||||
if (LIBCXX_ENABLE_EXPERIMENTAL_LIBRARY)
|
||||
set(LIBCXX_EXPERIMENTAL_SOURCES
|
||||
experimental/memory_resource.cpp
|
||||
)
|
||||
add_library(cxx_experimental STATIC ${LIBCXX_EXPERIMENTAL_SOURCES})
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
target_link_libraries(cxx_experimental PRIVATE cxx_shared)
|
||||
else()
|
||||
target_link_libraries(cxx_experimental PRIVATE cxx_static)
|
||||
endif()
|
||||
|
||||
set_target_properties(cxx_experimental
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}"
|
||||
OUTPUT_NAME "c++experimental"
|
||||
)
|
||||
cxx_add_common_build_flags(cxx_experimental)
|
||||
# Overwrite the previously-set Standard flag with -std=c++14 if supported
|
||||
check_flag_supported(-std=c++14)
|
||||
if (NOT MSVC AND LIBCXX_SUPPORTS_STD_EQ_CXX14_FLAG)
|
||||
target_compile_options(cxx_experimental PRIVATE "-std=c++14")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
if (LIBCXX_BUILD_EXTERNAL_THREAD_LIBRARY)
|
||||
file(GLOB LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES ../test/support/external_threads.cpp)
|
||||
|
||||
if (LIBCXX_ENABLE_SHARED)
|
||||
add_library(cxx_external_threads SHARED ${LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES})
|
||||
else()
|
||||
add_library(cxx_external_threads STATIC ${LIBCXX_EXTERNAL_THREADING_SUPPORT_SOURCES})
|
||||
endif()
|
||||
|
||||
set_target_properties(cxx_external_threads
|
||||
PROPERTIES
|
||||
LINK_FLAGS "${LIBCXX_LINK_FLAGS}"
|
||||
COMPILE_FLAGS "${LIBCXX_COMPILE_FLAGS}"
|
||||
OUTPUT_NAME "c++external_threads"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_INSTALL_LIBRARY)
|
||||
if (LIBCXX_INSTALL_SHARED_LIBRARY)
|
||||
install(TARGETS cxx_shared
|
||||
ARCHIVE DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
LIBRARY DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
RUNTIME DESTINATION ${LIBCXX_INSTALL_PREFIX}bin COMPONENT cxx)
|
||||
endif()
|
||||
|
||||
if (LIBCXX_INSTALL_STATIC_LIBRARY)
|
||||
install(TARGETS cxx_static
|
||||
ARCHIVE DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
LIBRARY DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
RUNTIME DESTINATION ${LIBCXX_INSTALL_PREFIX}bin COMPONENT cxx)
|
||||
endif()
|
||||
|
||||
if(LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY)
|
||||
install(TARGETS ${LIBCXX_INSTALL_TARGETS} ${experimental_lib}
|
||||
LIBRARY DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
ARCHIVE DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR} COMPONENT cxx
|
||||
RUNTIME DESTINATION ${LIBCXX_INSTALL_PREFIX}bin COMPONENT cxx)
|
||||
endif()
|
||||
|
||||
# NOTE: This install command must go after the cxx install command otherwise
|
||||
# it will not be executed after the library symlinks are installed.
|
||||
if (LIBCXX_ENABLE_SHARED AND LIBCXX_ENABLE_ABI_LINKER_SCRIPT)
|
||||
# Replace the libc++ filename with $<TARGET_LINKER_FILE:cxx>
|
||||
# after we required CMake 3.0.
|
||||
install(FILES "${LIBCXX_LIBRARY_DIR}/libc++${CMAKE_SHARED_LIBRARY_SUFFIX}"
|
||||
DESTINATION ${LIBCXX_INSTALL_PREFIX}${LIBCXX_INSTALL_LIBRARY_DIR}
|
||||
COMPONENT libcxx)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CONFIGURATION_TYPES AND (LIBCXX_INSTALL_LIBRARY OR
|
||||
LIBCXX_INSTALL_HEADERS))
|
||||
if(LIBCXX_INSTALL_LIBRARY)
|
||||
set(lib_install_target cxx)
|
||||
endif()
|
||||
if (LIBCXX_INSTALL_EXPERIMENTAL_LIBRARY)
|
||||
set(experimental_lib_install_target cxx_experimental)
|
||||
endif()
|
||||
if(LIBCXX_INSTALL_HEADERS)
|
||||
set(header_install_target install-cxx-headers)
|
||||
endif()
|
||||
add_custom_target(install-cxx
|
||||
DEPENDS ${lib_install_target}
|
||||
${experimental_lib_install_target}
|
||||
${header_install_target}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=cxx
|
||||
-P "${LIBCXX_BINARY_DIR}/cmake_install.cmake")
|
||||
add_custom_target(install-cxx-stripped
|
||||
DEPENDS ${lib_install_target}
|
||||
${experimental_lib_install_target}
|
||||
${header_install_target}
|
||||
COMMAND "${CMAKE_COMMAND}"
|
||||
-DCMAKE_INSTALL_COMPONENT=cxx
|
||||
-DCMAKE_INSTALL_DO_STRIP=1
|
||||
-P "${LIBCXX_BINARY_DIR}/cmake_install.cmake")
|
||||
add_custom_target(install-libcxx DEPENDS install-cxx)
|
||||
endif()
|
||||
|
|
@ -1,225 +0,0 @@
|
|||
# Check if lld is built as a standalone project.
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||
project(lld)
|
||||
cmake_minimum_required(VERSION 3.4.3)
|
||||
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(LLD_BUILT_STANDALONE TRUE)
|
||||
|
||||
find_program(LLVM_CONFIG_PATH "llvm-config" DOC "Path to llvm-config binary")
|
||||
if(NOT LLVM_CONFIG_PATH)
|
||||
message(FATAL_ERROR "llvm-config not found: specify LLVM_CONFIG_PATH")
|
||||
endif()
|
||||
|
||||
execute_process(COMMAND "${LLVM_CONFIG_PATH}"
|
||||
"--obj-root"
|
||||
"--includedir"
|
||||
"--cmakedir"
|
||||
"--src-root"
|
||||
RESULT_VARIABLE HAD_ERROR
|
||||
OUTPUT_VARIABLE LLVM_CONFIG_OUTPUT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(HAD_ERROR)
|
||||
message(FATAL_ERROR "llvm-config failed with status ${HAD_ERROR}")
|
||||
endif()
|
||||
|
||||
string(REGEX REPLACE "[ \t]*[\r\n]+[ \t]*" ";" LLVM_CONFIG_OUTPUT "${LLVM_CONFIG_OUTPUT}")
|
||||
|
||||
list(GET LLVM_CONFIG_OUTPUT 0 OBJ_ROOT)
|
||||
list(GET LLVM_CONFIG_OUTPUT 1 MAIN_INCLUDE_DIR)
|
||||
list(GET LLVM_CONFIG_OUTPUT 2 LLVM_CMAKE_PATH)
|
||||
list(GET LLVM_CONFIG_OUTPUT 3 MAIN_SRC_DIR)
|
||||
|
||||
set(LLVM_OBJ_ROOT ${OBJ_ROOT} CACHE PATH "path to LLVM build tree")
|
||||
set(LLVM_MAIN_INCLUDE_DIR ${MAIN_INCLUDE_DIR} CACHE PATH "path to llvm/include")
|
||||
set(LLVM_MAIN_SRC_DIR ${MAIN_SRC_DIR} CACHE PATH "Path to LLVM source tree")
|
||||
|
||||
file(TO_CMAKE_PATH ${LLVM_OBJ_ROOT} LLVM_BINARY_DIR)
|
||||
|
||||
if(NOT EXISTS "${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
|
||||
message(FATAL_ERROR "LLVMConfig.cmake not found")
|
||||
endif()
|
||||
include("${LLVM_CMAKE_PATH}/LLVMConfig.cmake")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
|
||||
|
||||
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
|
||||
include_directories("${LLVM_BINARY_DIR}/include" ${LLVM_INCLUDE_DIRS})
|
||||
link_directories(${LLVM_LIBRARY_DIRS})
|
||||
|
||||
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX})
|
||||
set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
|
||||
find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
include(AddLLVM)
|
||||
include(TableGen)
|
||||
include(HandleLLVMOptions)
|
||||
|
||||
if(LLVM_INCLUDE_TESTS)
|
||||
include(FindPythonInterp)
|
||||
if(NOT PYTHONINTERP_FOUND)
|
||||
message(FATAL_ERROR
|
||||
"Unable to find Python interpreter, required for testing.
|
||||
|
||||
Please install Python or specify the PYTHON_EXECUTABLE CMake variable.")
|
||||
endif()
|
||||
|
||||
if(${PYTHON_VERSION_STRING} VERSION_LESS 2.7)
|
||||
message(FATAL_ERROR "Python 2.7 or newer is required")
|
||||
endif()
|
||||
|
||||
# Check prebuilt llvm/utils.
|
||||
if(EXISTS ${LLVM_TOOLS_BINARY_DIR}/FileCheck${CMAKE_EXECUTABLE_SUFFIX}
|
||||
AND EXISTS ${LLVM_TOOLS_BINARY_DIR}/not${CMAKE_EXECUTABLE_SUFFIX})
|
||||
set(LLVM_UTILS_PROVIDED ON)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
|
||||
# Note: path not really used, except for checking if lit was found
|
||||
set(LLVM_LIT ${LLVM_MAIN_SRC_DIR}/utils/lit/lit.py)
|
||||
if(NOT LLVM_UTILS_PROVIDED)
|
||||
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/FileCheck utils/FileCheck)
|
||||
add_subdirectory(${LLVM_MAIN_SRC_DIR}/utils/not utils/not)
|
||||
set(LLVM_UTILS_PROVIDED ON)
|
||||
set(LLD_TEST_DEPS FileCheck not)
|
||||
endif()
|
||||
set(UNITTEST_DIR ${LLVM_MAIN_SRC_DIR}/utils/unittest)
|
||||
if(EXISTS ${UNITTEST_DIR}/googletest/include/gtest/gtest.h
|
||||
AND NOT EXISTS ${LLVM_LIBRARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}gtest${CMAKE_STATIC_LIBRARY_SUFFIX}
|
||||
AND EXISTS ${UNITTEST_DIR}/CMakeLists.txt)
|
||||
add_subdirectory(${UNITTEST_DIR} utils/unittest)
|
||||
endif()
|
||||
else()
|
||||
# Seek installed Lit.
|
||||
find_program(LLVM_LIT
|
||||
NAMES llvm-lit lit.py lit
|
||||
PATHS "${LLVM_MAIN_SRC_DIR}/utils/lit"
|
||||
DOC "Path to lit.py")
|
||||
endif()
|
||||
|
||||
if(LLVM_LIT)
|
||||
# Define the default arguments to use with 'lit', and an option for the user
|
||||
# to override.
|
||||
set(LIT_ARGS_DEFAULT "-sv")
|
||||
if (MSVC OR XCODE)
|
||||
set(LIT_ARGS_DEFAULT "${LIT_ARGS_DEFAULT} --no-progress-bar")
|
||||
endif()
|
||||
set(LLVM_LIT_ARGS "${LIT_ARGS_DEFAULT}" CACHE STRING "Default options for lit")
|
||||
|
||||
# On Win32 hosts, provide an option to specify the path to the GnuWin32 tools.
|
||||
if(WIN32 AND NOT CYGWIN)
|
||||
set(LLVM_LIT_TOOLS_DIR "" CACHE PATH "Path to GnuWin32 tools")
|
||||
endif()
|
||||
else()
|
||||
set(LLVM_INCLUDE_TESTS OFF)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LLD_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(LLD_INCLUDE_DIR ${LLD_SOURCE_DIR}/include )
|
||||
set(LLD_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
# Compute the LLD version from the LLVM version.
|
||||
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLD_VERSION
|
||||
${PACKAGE_VERSION})
|
||||
message(STATUS "LLD version: ${LLD_VERSION}")
|
||||
|
||||
string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.[0-9]+)?" "\\1" LLD_VERSION_MAJOR
|
||||
${LLD_VERSION})
|
||||
string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.[0-9]+)?" "\\1" LLD_VERSION_MINOR
|
||||
${LLD_VERSION})
|
||||
|
||||
# Determine LLD revision and repository.
|
||||
# TODO: Figure out a way to get the revision and the repository on windows.
|
||||
if ( NOT CMAKE_SYSTEM_NAME MATCHES "Windows" )
|
||||
execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetSourceVersion ${LLD_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE LLD_REVISION)
|
||||
|
||||
execute_process(COMMAND ${CMAKE_SOURCE_DIR}/utils/GetRepositoryPath ${LLD_SOURCE_DIR}
|
||||
OUTPUT_VARIABLE LLD_REPOSITORY)
|
||||
if ( LLD_REPOSITORY )
|
||||
# Replace newline characters with spaces
|
||||
string(REGEX REPLACE "(\r?\n)+" " " LLD_REPOSITORY ${LLD_REPOSITORY})
|
||||
# Remove leading spaces
|
||||
STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REPOSITORY "${LLD_REPOSITORY}" )
|
||||
# Remove trailing spaces
|
||||
string(REGEX REPLACE "(\ )+$" "" LLD_REPOSITORY ${LLD_REPOSITORY})
|
||||
endif()
|
||||
|
||||
if ( LLD_REVISION )
|
||||
# Replace newline characters with spaces
|
||||
string(REGEX REPLACE "(\r?\n)+" " " LLD_REVISION ${LLD_REVISION})
|
||||
# Remove leading spaces
|
||||
STRING(REGEX REPLACE "^[ \t\r\n]+" "" LLD_REVISION "${LLD_REVISION}" )
|
||||
# Remove trailing spaces
|
||||
string(REGEX REPLACE "(\ )+$" "" LLD_REVISION ${LLD_REVISION})
|
||||
endif()
|
||||
endif ()
|
||||
|
||||
# Configure the Version.inc file.
|
||||
configure_file(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include/lld/Common/Version.inc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/lld/Common/Version.inc)
|
||||
|
||||
|
||||
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
|
||||
"the makefiles distributed with LLVM. Please create a directory and run cmake "
|
||||
"from there, passing the path to this source directory as the last argument. "
|
||||
"This process created the file `CMakeCache.txt' and the directory "
|
||||
"`CMakeFiles'. Please delete them.")
|
||||
endif()
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH "${LLD_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
include(AddLLD)
|
||||
|
||||
option(LLD_USE_VTUNE
|
||||
"Enable VTune user task tracking."
|
||||
OFF)
|
||||
if (LLD_USE_VTUNE)
|
||||
find_package(VTune)
|
||||
if (VTUNE_FOUND)
|
||||
include_directories(${VTune_INCLUDE_DIRS})
|
||||
list(APPEND LLVM_COMMON_LIBS ${VTune_LIBRARIES})
|
||||
add_definitions(-DLLD_HAS_VTUNE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(LLD_BUILD_TOOLS
|
||||
"Build the lld tools. If OFF, just generate build targets." ON)
|
||||
|
||||
if (MSVC)
|
||||
add_definitions(-wd4530) # Suppress 'warning C4530: C++ exception handler used, but unwind semantics are not enabled.'
|
||||
add_definitions(-wd4062) # Suppress 'warning C4062: enumerator X in switch of enum Y is not handled' from system header.
|
||||
endif()
|
||||
|
||||
include_directories(BEFORE
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY)
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "*.h"
|
||||
PATTERN ".svn" EXCLUDE
|
||||
)
|
||||
endif()
|
||||
|
||||
add_subdirectory(Common)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(tools/lld)
|
||||
|
||||
if (LLVM_INCLUDE_TESTS)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(unittests)
|
||||
endif()
|
||||
|
||||
add_subdirectory(docs)
|
||||
add_subdirectory(COFF)
|
||||
add_subdirectory(ELF)
|
||||
add_subdirectory(MinGW)
|
||||
add_subdirectory(wasm)
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
set(LLVM_TARGET_DEFINITIONS Options.td)
|
||||
tablegen(LLVM Options.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(COFFOptionsTableGen)
|
||||
|
||||
if(NOT LLD_BUILT_STANDALONE)
|
||||
set(tablegen_deps intrinsics_gen)
|
||||
endif()
|
||||
|
||||
add_lld_library(lldCOFF
|
||||
Chunks.cpp
|
||||
DebugTypes.cpp
|
||||
DLL.cpp
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
ICF.cpp
|
||||
InputFiles.cpp
|
||||
LTO.cpp
|
||||
MapFile.cpp
|
||||
MarkLive.cpp
|
||||
MinGW.cpp
|
||||
PDB.cpp
|
||||
SymbolTable.cpp
|
||||
Symbols.cpp
|
||||
Writer.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
BinaryFormat
|
||||
Core
|
||||
DebugInfoCodeView
|
||||
DebugInfoDWARF
|
||||
DebugInfoMSF
|
||||
DebugInfoPDB
|
||||
Demangle
|
||||
LibDriver
|
||||
LTO
|
||||
MC
|
||||
Object
|
||||
Option
|
||||
Support
|
||||
WindowsManifest
|
||||
|
||||
LINK_LIBS
|
||||
lldCommon
|
||||
${LLVM_PTHREAD_LIB}
|
||||
|
||||
DEPENDS
|
||||
COFFOptionsTableGen
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
if(NOT LLD_BUILT_STANDALONE)
|
||||
set(tablegen_deps intrinsics_gen)
|
||||
endif()
|
||||
|
||||
find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc)
|
||||
find_first_existing_vc_file("${LLD_SOURCE_DIR}" lld_vc)
|
||||
|
||||
set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc")
|
||||
set(generate_vcs_version_script "${LLVM_CMAKE_PATH}/GenerateVersionFromVCS.cmake")
|
||||
|
||||
if(lld_vc)
|
||||
set(lld_source_dir ${LLD_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
add_custom_command(OUTPUT "${version_inc}"
|
||||
DEPENDS "${lld_vc}" "${generate_vcs_version_script}"
|
||||
COMMAND ${CMAKE_COMMAND} "-DNAMES=LLD"
|
||||
"-DLLD_SOURCE_DIR=${LLD_SOURCE_DIR}"
|
||||
"-DHEADER_FILE=${version_inc}"
|
||||
-P "${generate_vcs_version_script}")
|
||||
|
||||
# Mark the generated header as being generated.
|
||||
set_source_files_properties("${version_inc}"
|
||||
PROPERTIES GENERATED TRUE
|
||||
HEADER_FILE_ONLY TRUE)
|
||||
|
||||
set_property(SOURCE Version.cpp APPEND PROPERTY
|
||||
COMPILE_DEFINITIONS "HAVE_VCS_VERSION_INC")
|
||||
|
||||
add_lld_library(lldCommon
|
||||
Args.cpp
|
||||
DWARF.cpp
|
||||
ErrorHandler.cpp
|
||||
Filesystem.cpp
|
||||
Memory.cpp
|
||||
Reproduce.cpp
|
||||
Strings.cpp
|
||||
TargetOptionsCommandFlags.cpp
|
||||
Threads.cpp
|
||||
Timer.cpp
|
||||
VCSVersion.inc
|
||||
Version.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLD_INCLUDE_DIR}/lld/Common
|
||||
|
||||
LINK_COMPONENTS
|
||||
Codegen
|
||||
Core
|
||||
DebugInfoDWARF
|
||||
Demangle
|
||||
MC
|
||||
Option
|
||||
Support
|
||||
Target
|
||||
|
||||
LINK_LIBS
|
||||
${LLVM_PTHREAD_LIB}
|
||||
|
||||
DEPENDS
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
set(LLVM_TARGET_DEFINITIONS Options.td)
|
||||
tablegen(LLVM Options.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(ELFOptionsTableGen)
|
||||
|
||||
if(NOT LLD_BUILT_STANDALONE)
|
||||
set(tablegen_deps intrinsics_gen)
|
||||
endif()
|
||||
|
||||
add_lld_library(lldELF
|
||||
AArch64ErrataFix.cpp
|
||||
Arch/AArch64.cpp
|
||||
Arch/AMDGPU.cpp
|
||||
Arch/ARM.cpp
|
||||
Arch/AVR.cpp
|
||||
Arch/Hexagon.cpp
|
||||
Arch/Mips.cpp
|
||||
Arch/MipsArchTree.cpp
|
||||
Arch/MSP430.cpp
|
||||
Arch/PPC.cpp
|
||||
Arch/PPC64.cpp
|
||||
Arch/RISCV.cpp
|
||||
Arch/SPARCV9.cpp
|
||||
Arch/X86.cpp
|
||||
Arch/X86_64.cpp
|
||||
ARMErrataFix.cpp
|
||||
CallGraphSort.cpp
|
||||
DWARF.cpp
|
||||
Driver.cpp
|
||||
DriverUtils.cpp
|
||||
EhFrame.cpp
|
||||
ICF.cpp
|
||||
InputFiles.cpp
|
||||
InputSection.cpp
|
||||
LTO.cpp
|
||||
LinkerScript.cpp
|
||||
MapFile.cpp
|
||||
MarkLive.cpp
|
||||
OutputSections.cpp
|
||||
Relocations.cpp
|
||||
ScriptLexer.cpp
|
||||
ScriptParser.cpp
|
||||
SymbolTable.cpp
|
||||
Symbols.cpp
|
||||
SyntheticSections.cpp
|
||||
Target.cpp
|
||||
Thunks.cpp
|
||||
Writer.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
BinaryFormat
|
||||
BitWriter
|
||||
Core
|
||||
DebugInfoDWARF
|
||||
LTO
|
||||
MC
|
||||
Object
|
||||
Option
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
lldCommon
|
||||
${LLVM_PTHREAD_LIB}
|
||||
|
||||
DEPENDS
|
||||
ELFOptionsTableGen
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
if (LLVM_ENABLE_SPHINX)
|
||||
include(AddSphinxTarget)
|
||||
if (SPHINX_FOUND)
|
||||
if (${SPHINX_OUTPUT_HTML})
|
||||
add_sphinx_target(html lld)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
add_subdirectory(Core)
|
||||
add_subdirectory(Driver)
|
||||
add_subdirectory(ReaderWriter)
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
if(NOT LLD_BUILT_STANDALONE)
|
||||
set(tablegen_deps intrinsics_gen)
|
||||
endif()
|
||||
|
||||
add_lld_library(lldCore
|
||||
DefinedAtom.cpp
|
||||
Error.cpp
|
||||
File.cpp
|
||||
LinkingContext.cpp
|
||||
Reader.cpp
|
||||
Resolver.cpp
|
||||
SymbolTable.cpp
|
||||
Writer.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLD_INCLUDE_DIR}/lld/Core
|
||||
|
||||
LINK_COMPONENTS
|
||||
BinaryFormat
|
||||
MC
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
${LLVM_PTHREAD_LIB}
|
||||
|
||||
DEPENDS
|
||||
${tablegen_deps}
|
||||
)
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
set(LLVM_TARGET_DEFINITIONS DarwinLdOptions.td)
|
||||
tablegen(LLVM DarwinLdOptions.inc -gen-opt-parser-defs)
|
||||
add_public_tablegen_target(DriverOptionsTableGen)
|
||||
|
||||
add_lld_library(lldDriver
|
||||
DarwinLdDriver.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLD_INCLUDE_DIR}/lld/Driver
|
||||
|
||||
LINK_COMPONENTS
|
||||
Option
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
lldCommon
|
||||
lldCore
|
||||
lldMachO
|
||||
lldReaderWriter
|
||||
lldYAML
|
||||
)
|
||||
|
||||
add_dependencies(lldDriver DriverOptionsTableGen)
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
add_subdirectory(MachO)
|
||||
add_subdirectory(YAML)
|
||||
|
||||
if (MSVC)
|
||||
add_definitions(-wd4062) # Suppress 'warning C4062: Enumerator has no associated handler in a switch statement.'
|
||||
endif()
|
||||
|
||||
add_lld_library(lldReaderWriter
|
||||
FileArchive.cpp
|
||||
|
||||
ADDITIONAL_HEADER_DIRS
|
||||
${LLD_INCLUDE_DIR}/lld/ReaderWriter
|
||||
|
||||
LINK_COMPONENTS
|
||||
Object
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
lldCore
|
||||
)
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
add_lld_library(lldMachO
|
||||
ArchHandler.cpp
|
||||
ArchHandler_arm.cpp
|
||||
ArchHandler_arm64.cpp
|
||||
ArchHandler_x86.cpp
|
||||
ArchHandler_x86_64.cpp
|
||||
CompactUnwindPass.cpp
|
||||
GOTPass.cpp
|
||||
LayoutPass.cpp
|
||||
MachOLinkingContext.cpp
|
||||
MachONormalizedFileBinaryReader.cpp
|
||||
MachONormalizedFileBinaryWriter.cpp
|
||||
MachONormalizedFileFromAtoms.cpp
|
||||
MachONormalizedFileToAtoms.cpp
|
||||
MachONormalizedFileYAML.cpp
|
||||
ObjCPass.cpp
|
||||
ShimPass.cpp
|
||||
StubsPass.cpp
|
||||
TLVPass.cpp
|
||||
WriterMachO.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
DebugInfoDWARF
|
||||
Demangle
|
||||
Object
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
lldCommon
|
||||
lldCore
|
||||
lldYAML
|
||||
${LLVM_PTHREAD_LIB}
|
||||
)
|
||||
|
||||
include_directories(.)
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
add_lld_library(lldYAML
|
||||
ReaderWriterYAML.cpp
|
||||
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
|
||||
LINK_LIBS
|
||||
lldCore
|
||||
)
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
|
||||
add_lld_tool(lld
|
||||
lld.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(lld
|
||||
PRIVATE
|
||||
lldCommon
|
||||
lldCOFF
|
||||
lldDriver
|
||||
lldELF
|
||||
lldMinGW
|
||||
lldWasm
|
||||
)
|
||||
|
||||
install(TARGETS lld
|
||||
RUNTIME DESTINATION bin)
|
||||
|
||||
if(NOT LLD_SYMLINKS_TO_CREATE)
|
||||
set(LLD_SYMLINKS_TO_CREATE lld-link ld.lld ld64.lld wasm-ld)
|
||||
endif()
|
||||
|
||||
foreach(link ${LLD_SYMLINKS_TO_CREATE})
|
||||
add_lld_symlink(${link} lld)
|
||||
endforeach()
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
add_lldb_library(lldbPluginABISysV_arc PLUGIN
|
||||
ABISysV_arc.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Object
|
||||
Support
|
||||
TextAPI
|
||||
ObjectYAML
|
||||
)
|
||||
|
||||
add_llvm_tool(llvm-ifs
|
||||
llvm-ifs.cpp
|
||||
)
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
;===- ./tools/llvm-ifs/LLVMBuild.txt ---------------------------*- Conf -*--===;
|
||||
;
|
||||
; 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
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Tool
|
||||
name = llvm-ifs
|
||||
parent = Tools
|
||||
required_libraries = Object Support TextAPI
|
||||
|
|
@ -1,532 +0,0 @@
|
|||
//===- llvm-ifs.cpp -------------------------------------------------------===//
|
||||
//
|
||||
// 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/ADT/StringRef.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/ObjectYAML/yaml2obj.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Errc.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileOutputBuffer.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/VersionTuple.h"
|
||||
#include "llvm/Support/WithColor.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/TextAPI/MachO/InterfaceFile.h"
|
||||
#include "llvm/TextAPI/MachO/TextAPIReader.h"
|
||||
#include "llvm/TextAPI/MachO/TextAPIWriter.h"
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::yaml;
|
||||
using namespace llvm::MachO;
|
||||
|
||||
#define DEBUG_TYPE "llvm-ifs"
|
||||
|
||||
namespace {
|
||||
const VersionTuple IFSVersionCurrent(1, 2);
|
||||
}
|
||||
|
||||
static cl::opt<std::string> Action("action", cl::desc("<llvm-ifs action>"),
|
||||
cl::value_desc("write-ifs | write-bin"),
|
||||
cl::init("write-ifs"));
|
||||
|
||||
static cl::opt<std::string> ForceFormat("force-format",
|
||||
cl::desc("<force object format>"),
|
||||
cl::value_desc("ELF | TBD"),
|
||||
cl::init(""));
|
||||
|
||||
static cl::list<std::string> InputFilenames(cl::Positional,
|
||||
cl::desc("<input ifs files>"),
|
||||
cl::ZeroOrMore);
|
||||
|
||||
static cl::opt<std::string> OutputFilename("o", cl::desc("<output file>"),
|
||||
cl::value_desc("path"));
|
||||
|
||||
enum class IFSSymbolType {
|
||||
NoType = 0,
|
||||
Object,
|
||||
Func,
|
||||
// Type information is 4 bits, so 16 is safely out of range.
|
||||
Unknown = 16,
|
||||
};
|
||||
|
||||
std::string getTypeName(IFSSymbolType Type) {
|
||||
switch (Type) {
|
||||
case IFSSymbolType::NoType:
|
||||
return "NoType";
|
||||
case IFSSymbolType::Func:
|
||||
return "Func";
|
||||
case IFSSymbolType::Object:
|
||||
return "Object";
|
||||
case IFSSymbolType::Unknown:
|
||||
return "Unknown";
|
||||
}
|
||||
llvm_unreachable("Unexpected ifs symbol type.");
|
||||
}
|
||||
|
||||
struct IFSSymbol {
|
||||
IFSSymbol(std::string SymbolName) : Name(SymbolName) {}
|
||||
std::string Name;
|
||||
uint64_t Size;
|
||||
IFSSymbolType Type;
|
||||
bool Weak;
|
||||
Optional<std::string> Warning;
|
||||
bool operator<(const IFSSymbol &RHS) const { return Name < RHS.Name; }
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
/// YAML traits for IFSSymbolType.
|
||||
template <> struct ScalarEnumerationTraits<IFSSymbolType> {
|
||||
static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
|
||||
IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
|
||||
IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
|
||||
IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
|
||||
IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
|
||||
// Treat other symbol types as noise, and map to Unknown.
|
||||
if (!IO.outputting() && IO.matchEnumFallback())
|
||||
SymbolType = IFSSymbolType::Unknown;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<VersionTuple> {
|
||||
static void output(const VersionTuple &Value, void *,
|
||||
llvm::raw_ostream &Out) {
|
||||
Out << Value.getAsString();
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *, VersionTuple &Value) {
|
||||
if (Value.tryParse(Scalar))
|
||||
return StringRef("Can't parse version: invalid version format.");
|
||||
|
||||
if (Value > IFSVersionCurrent)
|
||||
return StringRef("Unsupported IFS version.");
|
||||
|
||||
// Returning empty StringRef indicates successful parse.
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
// Don't place quotation marks around version value.
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
||||
};
|
||||
|
||||
/// YAML traits for IFSSymbol.
|
||||
template <> struct MappingTraits<IFSSymbol> {
|
||||
static void mapping(IO &IO, IFSSymbol &Symbol) {
|
||||
IO.mapRequired("Type", Symbol.Type);
|
||||
// The need for symbol size depends on the symbol type.
|
||||
if (Symbol.Type == IFSSymbolType::NoType)
|
||||
IO.mapOptional("Size", Symbol.Size, (uint64_t)0);
|
||||
else if (Symbol.Type == IFSSymbolType::Func)
|
||||
Symbol.Size = 0;
|
||||
else
|
||||
IO.mapRequired("Size", Symbol.Size);
|
||||
IO.mapOptional("Weak", Symbol.Weak, false);
|
||||
IO.mapOptional("Warning", Symbol.Warning);
|
||||
}
|
||||
|
||||
// Compacts symbol information into a single line.
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
/// YAML traits for set of IFSSymbols.
|
||||
template <> struct CustomMappingTraits<std::set<IFSSymbol>> {
|
||||
static void inputOne(IO &IO, StringRef Key, std::set<IFSSymbol> &Set) {
|
||||
std::string Name = Key.str();
|
||||
IFSSymbol Sym(Name);
|
||||
IO.mapRequired(Name.c_str(), Sym);
|
||||
Set.insert(Sym);
|
||||
}
|
||||
|
||||
static void output(IO &IO, std::set<IFSSymbol> &Set) {
|
||||
for (auto &Sym : Set)
|
||||
IO.mapRequired(Sym.Name.c_str(), const_cast<IFSSymbol &>(Sym));
|
||||
}
|
||||
};
|
||||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
// A cumulative representation of ELF stubs.
|
||||
// Both textual and binary stubs will read into and write from this object.
|
||||
class IFSStub {
|
||||
// TODO: Add support for symbol versioning.
|
||||
public:
|
||||
VersionTuple IfsVersion;
|
||||
std::string Triple;
|
||||
std::string ObjectFileFormat;
|
||||
Optional<std::string> SOName;
|
||||
std::vector<std::string> NeededLibs;
|
||||
std::set<IFSSymbol> Symbols;
|
||||
|
||||
IFSStub() = default;
|
||||
IFSStub(const IFSStub &Stub)
|
||||
: IfsVersion(Stub.IfsVersion), Triple(Stub.Triple),
|
||||
ObjectFileFormat(Stub.ObjectFileFormat), SOName(Stub.SOName),
|
||||
NeededLibs(Stub.NeededLibs), Symbols(Stub.Symbols) {}
|
||||
IFSStub(IFSStub &&Stub)
|
||||
: IfsVersion(std::move(Stub.IfsVersion)), Triple(std::move(Stub.Triple)),
|
||||
ObjectFileFormat(std::move(Stub.ObjectFileFormat)),
|
||||
SOName(std::move(Stub.SOName)), NeededLibs(std::move(Stub.NeededLibs)),
|
||||
Symbols(std::move(Stub.Symbols)) {}
|
||||
};
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
/// YAML traits for IFSStub objects.
|
||||
template <> struct MappingTraits<IFSStub> {
|
||||
static void mapping(IO &IO, IFSStub &Stub) {
|
||||
if (!IO.mapTag("!experimental-ifs-v1", true))
|
||||
IO.setError("Not a .ifs YAML file.");
|
||||
IO.mapRequired("IfsVersion", Stub.IfsVersion);
|
||||
IO.mapOptional("Triple", Stub.Triple);
|
||||
IO.mapOptional("ObjectFileFormat", Stub.ObjectFileFormat);
|
||||
IO.mapOptional("SOName", Stub.SOName);
|
||||
IO.mapOptional("NeededLibs", Stub.NeededLibs);
|
||||
IO.mapRequired("Symbols", Stub.Symbols);
|
||||
}
|
||||
};
|
||||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
static Expected<std::unique_ptr<IFSStub>> readInputFile(StringRef FilePath) {
|
||||
// Read in file.
|
||||
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrError =
|
||||
MemoryBuffer::getFileOrSTDIN(FilePath);
|
||||
if (!BufOrError)
|
||||
return createStringError(BufOrError.getError(), "Could not open `%s`",
|
||||
FilePath.data());
|
||||
|
||||
std::unique_ptr<MemoryBuffer> FileReadBuffer = std::move(*BufOrError);
|
||||
yaml::Input YamlIn(FileReadBuffer->getBuffer());
|
||||
std::unique_ptr<IFSStub> Stub(new IFSStub());
|
||||
YamlIn >> *Stub;
|
||||
|
||||
if (std::error_code Err = YamlIn.error())
|
||||
return createStringError(Err, "Failed reading Interface Stub File.");
|
||||
|
||||
return std::move(Stub);
|
||||
}
|
||||
|
||||
int writeTbdStub(const llvm::Triple &T, const std::set<IFSSymbol> &Symbols,
|
||||
const StringRef Format, raw_ostream &Out) {
|
||||
|
||||
auto PlatformKindOrError =
|
||||
[](const llvm::Triple &T) -> llvm::Expected<llvm::MachO::PlatformKind> {
|
||||
if (T.isMacOSX())
|
||||
return llvm::MachO::PlatformKind::macOS;
|
||||
if (T.isTvOS())
|
||||
return llvm::MachO::PlatformKind::tvOS;
|
||||
if (T.isWatchOS())
|
||||
return llvm::MachO::PlatformKind::watchOS;
|
||||
// Note: put isiOS last because tvOS and watchOS are also iOS according
|
||||
// to the Triple.
|
||||
if (T.isiOS())
|
||||
return llvm::MachO::PlatformKind::iOS;
|
||||
|
||||
// TODO: Add an option for ForceTriple, but keep ForceFormat for now.
|
||||
if (ForceFormat == "TBD")
|
||||
return llvm::MachO::PlatformKind::macOS;
|
||||
|
||||
return createStringError(errc::not_supported, "Invalid Platform.\n");
|
||||
}(T);
|
||||
|
||||
if (!PlatformKindOrError)
|
||||
return -1;
|
||||
|
||||
PlatformKind Plat = PlatformKindOrError.get();
|
||||
TargetList Targets({Target(llvm::MachO::mapToArchitecture(T), Plat)});
|
||||
|
||||
InterfaceFile File;
|
||||
File.setFileType(FileType::TBD_V3); // Only supporting v3 for now.
|
||||
File.addTargets(Targets);
|
||||
|
||||
for (const auto &Symbol : Symbols) {
|
||||
auto Name = Symbol.Name;
|
||||
auto Kind = SymbolKind::GlobalSymbol;
|
||||
switch (Symbol.Type) {
|
||||
default:
|
||||
case IFSSymbolType::NoType:
|
||||
Kind = SymbolKind::GlobalSymbol;
|
||||
break;
|
||||
case IFSSymbolType::Object:
|
||||
Kind = SymbolKind::GlobalSymbol;
|
||||
break;
|
||||
case IFSSymbolType::Func:
|
||||
Kind = SymbolKind::GlobalSymbol;
|
||||
break;
|
||||
}
|
||||
if (Symbol.Weak)
|
||||
File.addSymbol(Kind, Name, Targets, SymbolFlags::WeakDefined);
|
||||
else
|
||||
File.addSymbol(Kind, Name, Targets);
|
||||
}
|
||||
|
||||
SmallString<4096> Buffer;
|
||||
raw_svector_ostream OS(Buffer);
|
||||
if (Error Result = TextAPIWriter::writeToStream(OS, File))
|
||||
return -1;
|
||||
Out << OS.str();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int writeElfStub(const llvm::Triple &T, const std::set<IFSSymbol> &Symbols,
|
||||
const StringRef Format, raw_ostream &Out) {
|
||||
SmallString<0> Storage;
|
||||
Storage.clear();
|
||||
raw_svector_ostream OS(Storage);
|
||||
|
||||
OS << "--- !ELF\n";
|
||||
OS << "FileHeader:\n";
|
||||
OS << " Class: ELFCLASS";
|
||||
OS << (T.isArch64Bit() ? "64" : "32");
|
||||
OS << "\n";
|
||||
OS << " Data: ELFDATA2";
|
||||
OS << (T.isLittleEndian() ? "LSB" : "MSB");
|
||||
OS << "\n";
|
||||
OS << " Type: ET_DYN\n";
|
||||
OS << " Machine: "
|
||||
<< llvm::StringSwitch<llvm::StringRef>(T.getArchName())
|
||||
.Case("x86_64", "EM_X86_64")
|
||||
.Case("i386", "EM_386")
|
||||
.Case("i686", "EM_386")
|
||||
.Case("aarch64", "EM_AARCH64")
|
||||
.Case("amdgcn", "EM_AMDGPU")
|
||||
.Case("r600", "EM_AMDGPU")
|
||||
.Case("arm", "EM_ARM")
|
||||
.Case("thumb", "EM_ARM")
|
||||
.Case("avr", "EM_AVR")
|
||||
.Case("mips", "EM_MIPS")
|
||||
.Case("mipsel", "EM_MIPS")
|
||||
.Case("mips64", "EM_MIPS")
|
||||
.Case("mips64el", "EM_MIPS")
|
||||
.Case("msp430", "EM_MSP430")
|
||||
.Case("ppc", "EM_PPC")
|
||||
.Case("ppc64", "EM_PPC64")
|
||||
.Case("ppc64le", "EM_PPC64")
|
||||
.Case("x86", T.isOSIAMCU() ? "EM_IAMCU" : "EM_386")
|
||||
.Case("x86_64", "EM_X86_64")
|
||||
.Default("EM_NONE")
|
||||
<< "\nSections:"
|
||||
<< "\n - Name: .text"
|
||||
<< "\n Type: SHT_PROGBITS"
|
||||
<< "\n - Name: .data"
|
||||
<< "\n Type: SHT_PROGBITS"
|
||||
<< "\n - Name: .rodata"
|
||||
<< "\n Type: SHT_PROGBITS"
|
||||
<< "\nSymbols:\n";
|
||||
for (const auto &Symbol : Symbols) {
|
||||
OS << " - Name: " << Symbol.Name << "\n"
|
||||
<< " Type: STT_";
|
||||
switch (Symbol.Type) {
|
||||
default:
|
||||
case IFSSymbolType::NoType:
|
||||
OS << "NOTYPE";
|
||||
break;
|
||||
case IFSSymbolType::Object:
|
||||
OS << "OBJECT";
|
||||
break;
|
||||
case IFSSymbolType::Func:
|
||||
OS << "FUNC";
|
||||
break;
|
||||
}
|
||||
OS << "\n Section: .text"
|
||||
<< "\n Binding: STB_" << (Symbol.Weak ? "WEAK" : "GLOBAL")
|
||||
<< "\n";
|
||||
}
|
||||
OS << "...\n";
|
||||
|
||||
std::string YamlStr = OS.str();
|
||||
|
||||
// Only or debugging. Not an offical format.
|
||||
LLVM_DEBUG({
|
||||
if (ForceFormat == "ELFOBJYAML") {
|
||||
Out << YamlStr;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
yaml::Input YIn(YamlStr);
|
||||
auto ErrHandler = [](const Twine &Msg) {
|
||||
WithColor::error(errs(), "llvm-ifs") << Msg << "\n";
|
||||
};
|
||||
return convertYAML(YIn, Out, ErrHandler) ? 0 : 1;
|
||||
}
|
||||
|
||||
int writeIfso(const IFSStub &Stub, bool IsWriteIfs, raw_ostream &Out) {
|
||||
if (IsWriteIfs) {
|
||||
yaml::Output YamlOut(Out, NULL, /*WrapColumn =*/0);
|
||||
YamlOut << const_cast<IFSStub &>(Stub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string ObjectFileFormat =
|
||||
ForceFormat.empty() ? Stub.ObjectFileFormat : ForceFormat;
|
||||
|
||||
if (ObjectFileFormat == "ELF" || ForceFormat == "ELFOBJYAML")
|
||||
return writeElfStub(llvm::Triple(Stub.Triple), Stub.Symbols,
|
||||
Stub.ObjectFileFormat, Out);
|
||||
if (ObjectFileFormat == "TBD")
|
||||
return writeTbdStub(llvm::Triple(Stub.Triple), Stub.Symbols,
|
||||
Stub.ObjectFileFormat, Out);
|
||||
|
||||
WithColor::error()
|
||||
<< "Invalid ObjectFileFormat: Only ELF and TBD are supported.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// New Interface Stubs Yaml Format:
|
||||
// --- !experimental-ifs-v1
|
||||
// IfsVersion: 1.0
|
||||
// Triple: <llvm triple>
|
||||
// ObjectFileFormat: <ELF | others not yet supported>
|
||||
// Symbols:
|
||||
// _ZSymbolName: { Type: <type> }
|
||||
// ...
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// Parse arguments.
|
||||
cl::ParseCommandLineOptions(argc, argv);
|
||||
|
||||
if (InputFilenames.empty())
|
||||
InputFilenames.push_back("-");
|
||||
|
||||
IFSStub Stub;
|
||||
std::map<std::string, IFSSymbol> SymbolMap;
|
||||
|
||||
std::string PreviousInputFilePath = "";
|
||||
for (const std::string &InputFilePath : InputFilenames) {
|
||||
Expected<std::unique_ptr<IFSStub>> StubOrErr = readInputFile(InputFilePath);
|
||||
if (!StubOrErr) {
|
||||
WithColor::error() << StubOrErr.takeError() << "\n";
|
||||
return -1;
|
||||
}
|
||||
std::unique_ptr<IFSStub> TargetStub = std::move(StubOrErr.get());
|
||||
|
||||
if (Stub.Triple.empty()) {
|
||||
PreviousInputFilePath = InputFilePath;
|
||||
Stub.IfsVersion = TargetStub->IfsVersion;
|
||||
Stub.Triple = TargetStub->Triple;
|
||||
Stub.ObjectFileFormat = TargetStub->ObjectFileFormat;
|
||||
Stub.SOName = TargetStub->SOName;
|
||||
Stub.NeededLibs = TargetStub->NeededLibs;
|
||||
} else {
|
||||
if (Stub.IfsVersion != TargetStub->IfsVersion) {
|
||||
if (Stub.IfsVersion.getMajor() != IFSVersionCurrent.getMajor()) {
|
||||
WithColor::error()
|
||||
<< "Interface Stub: IfsVersion Mismatch."
|
||||
<< "\nFilenames: " << PreviousInputFilePath << " "
|
||||
<< InputFilePath << "\nIfsVersion Values: " << Stub.IfsVersion
|
||||
<< " " << TargetStub->IfsVersion << "\n";
|
||||
return -1;
|
||||
}
|
||||
if (TargetStub->IfsVersion > Stub.IfsVersion)
|
||||
Stub.IfsVersion = TargetStub->IfsVersion;
|
||||
}
|
||||
if (Stub.ObjectFileFormat != TargetStub->ObjectFileFormat) {
|
||||
WithColor::error() << "Interface Stub: ObjectFileFormat Mismatch."
|
||||
<< "\nFilenames: " << PreviousInputFilePath << " "
|
||||
<< InputFilePath << "\nObjectFileFormat Values: "
|
||||
<< Stub.ObjectFileFormat << " "
|
||||
<< TargetStub->ObjectFileFormat << "\n";
|
||||
return -1;
|
||||
}
|
||||
if (Stub.Triple != TargetStub->Triple) {
|
||||
WithColor::error() << "Interface Stub: Triple Mismatch."
|
||||
<< "\nFilenames: " << PreviousInputFilePath << " "
|
||||
<< InputFilePath
|
||||
<< "\nTriple Values: " << Stub.Triple << " "
|
||||
<< TargetStub->Triple << "\n";
|
||||
return -1;
|
||||
}
|
||||
if (Stub.SOName != TargetStub->SOName) {
|
||||
WithColor::error() << "Interface Stub: SOName Mismatch."
|
||||
<< "\nFilenames: " << PreviousInputFilePath << " "
|
||||
<< InputFilePath
|
||||
<< "\nSOName Values: " << Stub.SOName << " "
|
||||
<< TargetStub->SOName << "\n";
|
||||
return -1;
|
||||
}
|
||||
if (Stub.NeededLibs != TargetStub->NeededLibs) {
|
||||
WithColor::error() << "Interface Stub: NeededLibs Mismatch."
|
||||
<< "\nFilenames: " << PreviousInputFilePath << " "
|
||||
<< InputFilePath << "\n";
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto Symbol : TargetStub->Symbols) {
|
||||
auto SI = SymbolMap.find(Symbol.Name);
|
||||
if (SI == SymbolMap.end()) {
|
||||
SymbolMap.insert(
|
||||
std::pair<std::string, IFSSymbol>(Symbol.Name, Symbol));
|
||||
continue;
|
||||
}
|
||||
|
||||
assert(Symbol.Name == SI->second.Name && "Symbol Names Must Match.");
|
||||
|
||||
// Check conflicts:
|
||||
if (Symbol.Type != SI->second.Type) {
|
||||
WithColor::error() << "Interface Stub: Type Mismatch for "
|
||||
<< Symbol.Name << ".\nFilename: " << InputFilePath
|
||||
<< "\nType Values: " << getTypeName(SI->second.Type)
|
||||
<< " " << getTypeName(Symbol.Type) << "\n";
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (Symbol.Size != SI->second.Size) {
|
||||
WithColor::error() << "Interface Stub: Size Mismatch for "
|
||||
<< Symbol.Name << ".\nFilename: " << InputFilePath
|
||||
<< "\nSize Values: " << SI->second.Size << " "
|
||||
<< Symbol.Size << "\n";
|
||||
|
||||
return -1;
|
||||
}
|
||||
if (Symbol.Weak != SI->second.Weak) {
|
||||
// TODO: Add conflict resolution for Weak vs non-Weak.
|
||||
WithColor::error() << "Interface Stub: Weak Mismatch for "
|
||||
<< Symbol.Name << ".\nFilename: " << InputFilePath
|
||||
<< "\nWeak Values: " << SI->second.Weak << " "
|
||||
<< Symbol.Weak << "\n";
|
||||
|
||||
return -1;
|
||||
}
|
||||
// TODO: Not checking Warning. Will be dropped.
|
||||
}
|
||||
|
||||
PreviousInputFilePath = InputFilePath;
|
||||
}
|
||||
|
||||
if (Stub.IfsVersion != IFSVersionCurrent)
|
||||
if (Stub.IfsVersion.getMajor() != IFSVersionCurrent.getMajor()) {
|
||||
WithColor::error() << "Interface Stub: Bad IfsVersion: "
|
||||
<< Stub.IfsVersion << ", llvm-ifs supported version: "
|
||||
<< IFSVersionCurrent << ".\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (auto &Entry : SymbolMap)
|
||||
Stub.Symbols.insert(Entry.second);
|
||||
|
||||
std::error_code SysErr;
|
||||
|
||||
// Open file for writing.
|
||||
raw_fd_ostream Out(OutputFilename, SysErr);
|
||||
if (SysErr) {
|
||||
WithColor::error() << "Couldn't open " << OutputFilename
|
||||
<< " for writing.\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
return writeIfso(Stub, (Action == "write-ifs"), Out);
|
||||
}
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
AllTargetsAsmParsers
|
||||
AllTargetsCodeGens
|
||||
AllTargetsDescs
|
||||
AllTargetsInfos
|
||||
Core
|
||||
IRReader
|
||||
Support
|
||||
Target
|
||||
TransformUtils
|
||||
)
|
||||
|
||||
add_llvm_tool(llvm-reduce
|
||||
llvm-reduce.cpp
|
||||
TestRunner.cpp
|
||||
deltas/Delta.cpp
|
||||
deltas/ReduceFunctions.cpp
|
||||
deltas/ReduceGlobalVars.cpp
|
||||
deltas/ReduceMetadata.cpp
|
||||
deltas/ReduceArguments.cpp
|
||||
deltas/ReduceBasicBlocks.cpp
|
||||
deltas/ReduceInstructions.cpp
|
||||
|
||||
DEPENDS
|
||||
intrinsics_gen
|
||||
)
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
//===- DeltaManager.h - Runs Delta Passes to reduce Input -----------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file calls each specialized Delta pass in order to reduce the input IR
|
||||
// file.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TestRunner.h"
|
||||
#include "deltas/Delta.h"
|
||||
#include "deltas/ReduceArguments.h"
|
||||
#include "deltas/ReduceBasicBlocks.h"
|
||||
#include "deltas/ReduceFunctions.h"
|
||||
#include "deltas/ReduceGlobalVars.h"
|
||||
#include "deltas/ReduceMetadata.h"
|
||||
#include "deltas/ReduceInstructions.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// TODO: Add CLI option to run only specified Passes (for unit tests)
|
||||
inline void runDeltaPasses(TestRunner &Tester) {
|
||||
reduceFunctionsDeltaPass(Tester);
|
||||
reduceBasicBlocksDeltaPass(Tester);
|
||||
reduceGlobalsDeltaPass(Tester);
|
||||
reduceMetadataDeltaPass(Tester);
|
||||
reduceArgumentsDeltaPass(Tester);
|
||||
reduceInstructionsDeltaPass(Tester);
|
||||
// TODO: Implement the remaining Delta Passes
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
;===- ./tools/llvm-reduce/LLVMBuild.txt ------------------------*- Conf -*--===;
|
||||
;
|
||||
; 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
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Tool
|
||||
name = llvm-reduce
|
||||
parent = Tools
|
||||
required_libraries =
|
||||
BitReader
|
||||
IRReader
|
||||
all-targets
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
//===-- TestRunner.cpp ----------------------------------------------------===//
|
||||
//
|
||||
// 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 "TestRunner.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
TestRunner::TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs)
|
||||
: TestName(TestName), TestArgs(TestArgs) {
|
||||
}
|
||||
|
||||
/// Runs the interestingness test, passes file to be tested as first argument
|
||||
/// and other specified test arguments after that.
|
||||
int TestRunner::run(StringRef Filename) {
|
||||
std::vector<StringRef> ProgramArgs;
|
||||
ProgramArgs.push_back(TestName);
|
||||
|
||||
for (const auto &Arg : TestArgs)
|
||||
ProgramArgs.push_back(Arg);
|
||||
|
||||
ProgramArgs.push_back(Filename);
|
||||
|
||||
std::string ErrMsg;
|
||||
int Result = sys::ExecuteAndWait(
|
||||
TestName, ProgramArgs, /*Env=*/None, /*Redirects=*/None,
|
||||
/*SecondsToWait=*/0, /*MemoryLimit=*/0, &ErrMsg);
|
||||
|
||||
if (Result < 0) {
|
||||
Error E = make_error<StringError>("Error running interesting-ness test: " +
|
||||
ErrMsg,
|
||||
inconvertibleErrorCode());
|
||||
errs() << toString(std::move(E));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return !Result;
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
//===-- tools/llvm-reduce/TestRunner.h ---------------------------*- 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_TOOLS_LLVMREDUCE_TESTRUNNER_H
|
||||
#define LLVM_TOOLS_LLVMREDUCE_TESTRUNNER_H
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/Path.h"
|
||||
#include "llvm/Support/Program.h"
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// This class contains all the info necessary for running the provided
|
||||
// interesting-ness test, as well as the most reduced module and its
|
||||
// respective filename.
|
||||
class TestRunner {
|
||||
public:
|
||||
TestRunner(StringRef TestName, const std::vector<std::string> &TestArgs);
|
||||
|
||||
/// Runs the interesting-ness test for the specified file
|
||||
/// @returns 0 if test was successful, 1 if otherwise
|
||||
int run(StringRef Filename);
|
||||
|
||||
/// Returns the most reduced version of the original testcase
|
||||
Module *getProgram() const { return Program.get(); }
|
||||
|
||||
void setProgram(std::unique_ptr<Module> P) { Program = std::move(P); }
|
||||
|
||||
private:
|
||||
StringRef TestName;
|
||||
const std::vector<std::string> &TestArgs;
|
||||
std::unique_ptr<Module> Program;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
//===- Delta.cpp - Delta Debugging Algorithm Implementation ---------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the implementation for the Delta Debugging Algorithm:
|
||||
// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
|
||||
// into chunks and tries to reduce the number chunks that are interesting.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/ToolOutputFile.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
bool IsReduced(Module &M, TestRunner &Test, SmallString<128> &CurrentFilepath) {
|
||||
// Write Module to tmp file
|
||||
int FD;
|
||||
std::error_code EC =
|
||||
sys::fs::createTemporaryFile("llvm-reduce", "ll", FD, CurrentFilepath);
|
||||
if (EC) {
|
||||
errs() << "Error making unique filename: " << EC.message() << "!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ToolOutputFile Out(CurrentFilepath, FD);
|
||||
M.print(Out.os(), /*AnnotationWriter=*/nullptr);
|
||||
Out.os().close();
|
||||
if (Out.os().has_error()) {
|
||||
errs() << "Error emitting bitcode to file '" << CurrentFilepath << "'!\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Current Chunks aren't interesting
|
||||
return Test.run(CurrentFilepath);
|
||||
}
|
||||
|
||||
/// Counts the amount of lines for a given file
|
||||
static int getLines(StringRef Filepath) {
|
||||
int Lines = 0;
|
||||
std::string CurrLine;
|
||||
std::ifstream FileStream(Filepath);
|
||||
|
||||
while (std::getline(FileStream, CurrLine))
|
||||
++Lines;
|
||||
|
||||
return Lines;
|
||||
}
|
||||
|
||||
/// Splits Chunks in half and prints them.
|
||||
/// If unable to split (when chunk size is 1) returns false.
|
||||
static bool increaseGranularity(std::vector<Chunk> &Chunks) {
|
||||
errs() << "Increasing granularity...";
|
||||
std::vector<Chunk> NewChunks;
|
||||
bool SplitOne = false;
|
||||
|
||||
for (auto &C : Chunks) {
|
||||
if (C.end - C.begin == 0)
|
||||
NewChunks.push_back(C);
|
||||
else {
|
||||
int Half = (C.begin + C.end) / 2;
|
||||
NewChunks.push_back({C.begin, Half});
|
||||
NewChunks.push_back({Half + 1, C.end});
|
||||
SplitOne = true;
|
||||
}
|
||||
}
|
||||
if (SplitOne) {
|
||||
Chunks = NewChunks;
|
||||
errs() << "Success! New Chunks:\n";
|
||||
for (auto C : Chunks) {
|
||||
errs() << '\t';
|
||||
C.print();
|
||||
errs() << '\n';
|
||||
}
|
||||
}
|
||||
return SplitOne;
|
||||
}
|
||||
|
||||
/// Runs the Delta Debugging algorithm, splits the code into chunks and
|
||||
/// reduces the amount of chunks that are considered interesting by the
|
||||
/// given test.
|
||||
void llvm::runDeltaPass(
|
||||
TestRunner &Test, int Targets,
|
||||
std::function<void(const std::vector<Chunk> &, Module *)>
|
||||
ExtractChunksFromModule) {
|
||||
assert(Targets >= 0);
|
||||
if (!Targets) {
|
||||
errs() << "\nNothing to reduce\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Module *Program = Test.getProgram()) {
|
||||
SmallString<128> CurrentFilepath;
|
||||
if (!IsReduced(*Program, Test, CurrentFilepath)) {
|
||||
errs() << "\nInput isn't interesting! Verify interesting-ness test\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Chunk> Chunks = {{1, Targets}};
|
||||
std::set<Chunk> UninterestingChunks;
|
||||
std::unique_ptr<Module> ReducedProgram;
|
||||
|
||||
if (!increaseGranularity(Chunks)) {
|
||||
errs() << "\nAlready at minimum size. Cannot reduce anymore.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
UninterestingChunks = {};
|
||||
for (int I = Chunks.size() - 1; I >= 0; --I) {
|
||||
std::vector<Chunk> CurrentChunks;
|
||||
|
||||
for (auto C : Chunks)
|
||||
if (!UninterestingChunks.count(C) && C != Chunks[I])
|
||||
CurrentChunks.push_back(C);
|
||||
|
||||
if (CurrentChunks.empty())
|
||||
continue;
|
||||
|
||||
// Clone module before hacking it up..
|
||||
std::unique_ptr<Module> Clone = CloneModule(*Test.getProgram());
|
||||
// Generate Module with only Targets inside Current Chunks
|
||||
ExtractChunksFromModule(CurrentChunks, Clone.get());
|
||||
|
||||
errs() << "Ignoring: ";
|
||||
Chunks[I].print();
|
||||
for (auto C : UninterestingChunks)
|
||||
C.print();
|
||||
|
||||
|
||||
|
||||
SmallString<128> CurrentFilepath;
|
||||
if (!IsReduced(*Clone, Test, CurrentFilepath)) {
|
||||
errs() << "\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
UninterestingChunks.insert(Chunks[I]);
|
||||
ReducedProgram = std::move(Clone);
|
||||
errs() << " **** SUCCESS | lines: " << getLines(CurrentFilepath) << "\n";
|
||||
}
|
||||
// Delete uninteresting chunks
|
||||
erase_if(Chunks, [&UninterestingChunks](const Chunk &C) {
|
||||
return UninterestingChunks.count(C);
|
||||
});
|
||||
|
||||
} while (!UninterestingChunks.empty() || increaseGranularity(Chunks));
|
||||
|
||||
// If we reduced the testcase replace it
|
||||
if (ReducedProgram)
|
||||
Test.setProgram(std::move(ReducedProgram));
|
||||
errs() << "Couldn't increase anymore.\n";
|
||||
}
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
//===- Delta.h - Delta Debugging Algorithm Implementation -----------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the implementation for the Delta Debugging Algorithm:
|
||||
// it splits a given set of Targets (i.e. Functions, Instructions, BBs, etc.)
|
||||
// into chunks and tries to reduce the number chunks that are interesting.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H
|
||||
#define LLVM_TOOLS_LLVMREDUCE_LLVMREDUCE_DELTA_H
|
||||
|
||||
#include "TestRunner.h"
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct Chunk {
|
||||
int begin;
|
||||
int end;
|
||||
|
||||
/// Helper function to verify if a given Target-index is inside the Chunk
|
||||
bool contains(int Index) const { return Index >= begin && Index <= end; }
|
||||
|
||||
void print() const {
|
||||
errs() << "[" << begin;
|
||||
if (end - begin != 0)
|
||||
errs() << "," << end;
|
||||
errs() << "]";
|
||||
}
|
||||
|
||||
/// Operator when populating CurrentChunks in Generic Delta Pass
|
||||
friend bool operator!=(const Chunk &C1, const Chunk &C2) {
|
||||
return C1.begin != C2.begin || C1.end != C2.end;
|
||||
}
|
||||
|
||||
/// Operator used for sets
|
||||
friend bool operator<(const Chunk &C1, const Chunk &C2) {
|
||||
return std::tie(C1.begin, C1.end) < std::tie(C2.begin, C2.end);
|
||||
}
|
||||
};
|
||||
|
||||
/// This function implements the Delta Debugging algorithm, it receives a
|
||||
/// number of Targets (e.g. Functions, Instructions, Basic Blocks, etc.) and
|
||||
/// splits them in half; these chunks of targets are then tested while ignoring
|
||||
/// one chunk, if a chunk is proven to be uninteresting (i.e. fails the test)
|
||||
/// it is removed from consideration. The algorithm will attempt to split the
|
||||
/// Chunks in half and start the process again until it can't split chunks
|
||||
/// anymore.
|
||||
///
|
||||
/// This function is intended to be called by each specialized delta pass (e.g.
|
||||
/// RemoveFunctions) and receives three key parameters:
|
||||
/// * Test: The main TestRunner instance which is used to run the provided
|
||||
/// interesting-ness test, as well as to store and access the reduced Program.
|
||||
/// * Targets: The amount of Targets that are going to be reduced by the
|
||||
/// algorithm, for example, the RemoveGlobalVars pass would send the amount of
|
||||
/// initialized GVs.
|
||||
/// * ExtractChunksFromModule: A function used to tailor the main program so it
|
||||
/// only contains Targets that are inside Chunks of the given iteration.
|
||||
/// Note: This function is implemented by each specialized Delta pass
|
||||
///
|
||||
/// Other implementations of the Delta Debugging algorithm can also be found in
|
||||
/// the CReduce, Delta, and Lithium projects.
|
||||
void runDeltaPass(TestRunner &Test, int Targets,
|
||||
std::function<void(const std::vector<Chunk> &, Module *)>
|
||||
ExtractChunksFromModule);
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceArguments.h"
|
||||
#include "Delta.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Goes over OldF calls and replaces them with a call to NewF
|
||||
static void replaceFunctionCalls(Function &OldF, Function &NewF,
|
||||
const std::set<int> &ArgIndexesToKeep) {
|
||||
const auto &Users = OldF.users();
|
||||
for (auto I = Users.begin(), E = Users.end(); I != E; )
|
||||
if (auto *CI = dyn_cast<CallInst>(*I++)) {
|
||||
SmallVector<Value *, 8> Args;
|
||||
for (auto ArgI = CI->arg_begin(), E = CI->arg_end(); ArgI != E; ++ArgI)
|
||||
if (ArgIndexesToKeep.count(ArgI - CI->arg_begin()))
|
||||
Args.push_back(*ArgI);
|
||||
|
||||
CallInst *NewCI = CallInst::Create(&NewF, Args);
|
||||
NewCI->setCallingConv(NewF.getCallingConv());
|
||||
if (!CI->use_empty())
|
||||
CI->replaceAllUsesWith(NewCI);
|
||||
ReplaceInstWithInst(CI, NewCI);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes out-of-chunk arguments from functions, and modifies their calls
|
||||
/// accordingly. It also removes allocations of out-of-chunk arguments.
|
||||
static void extractArgumentsFromModule(std::vector<Chunk> ChunksToKeep,
|
||||
Module *Program) {
|
||||
int I = 0, ArgCount = 0;
|
||||
std::set<Argument *> ArgsToKeep;
|
||||
std::vector<Function *> Funcs;
|
||||
// Get inside-chunk arguments, as well as their parent function
|
||||
for (auto &F : *Program)
|
||||
if (!F.isDeclaration()) {
|
||||
Funcs.push_back(&F);
|
||||
for (auto &A : F.args())
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(++ArgCount))
|
||||
ArgsToKeep.insert(&A);
|
||||
if (ChunksToKeep[I].end == ArgCount)
|
||||
++I;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto *F : Funcs) {
|
||||
ValueToValueMapTy VMap;
|
||||
std::vector<Instruction *> InstToDelete;
|
||||
for (auto &A : F->args())
|
||||
if (!ArgsToKeep.count(&A)) {
|
||||
// By adding undesired arguments to the VMap, CloneFunction will remove
|
||||
// them from the resulting Function
|
||||
VMap[&A] = UndefValue::get(A.getType());
|
||||
for (auto *U : A.users())
|
||||
if (auto *I = dyn_cast<Instruction>(*&U))
|
||||
InstToDelete.push_back(I);
|
||||
}
|
||||
// Delete any instruction that uses the argument
|
||||
for (auto *I : InstToDelete) {
|
||||
I->replaceAllUsesWith(UndefValue::get(I->getType()));
|
||||
I->eraseFromParent();
|
||||
}
|
||||
|
||||
// No arguments to reduce
|
||||
if (VMap.empty())
|
||||
continue;
|
||||
|
||||
std::set<int> ArgIndexesToKeep;
|
||||
int ArgI = 0;
|
||||
for (auto &Arg : F->args())
|
||||
if (ArgsToKeep.count(&Arg))
|
||||
ArgIndexesToKeep.insert(++ArgI);
|
||||
|
||||
auto *ClonedFunc = CloneFunction(F, VMap);
|
||||
// In order to preserve function order, we move Clone after old Function
|
||||
ClonedFunc->removeFromParent();
|
||||
Program->getFunctionList().insertAfter(F->getIterator(), ClonedFunc);
|
||||
|
||||
replaceFunctionCalls(*F, *ClonedFunc, ArgIndexesToKeep);
|
||||
// Rename Cloned Function to Old's name
|
||||
std::string FName = F->getName();
|
||||
F->eraseFromParent();
|
||||
ClonedFunc->setName(FName);
|
||||
}
|
||||
}
|
||||
|
||||
/// Counts the amount of arguments in non-declaration functions and prints their
|
||||
/// respective name, index, and parent function name
|
||||
static int countArguments(Module *Program) {
|
||||
// TODO: Silence index with --quiet flag
|
||||
outs() << "----------------------------\n";
|
||||
outs() << "Param Index Reference:\n";
|
||||
int ArgsCount = 0;
|
||||
for (auto &F : *Program)
|
||||
if (!F.isDeclaration() && F.arg_size()) {
|
||||
outs() << " " << F.getName() << "\n";
|
||||
for (auto &A : F.args())
|
||||
outs() << "\t" << ++ArgsCount << ": " << A.getName() << "\n";
|
||||
|
||||
outs() << "----------------------------\n";
|
||||
}
|
||||
|
||||
return ArgsCount;
|
||||
}
|
||||
|
||||
void llvm::reduceArgumentsDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Arguments...\n";
|
||||
int ArgCount = countArguments(Test.getProgram());
|
||||
runDeltaPass(Test, ArgCount, extractArgumentsFromModule);
|
||||
}
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/IR/Argument.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceArgumentsDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceBasicBlocks.h"
|
||||
#include "llvm/IR/BasicBlock.h"
|
||||
#include "llvm/IR/Instruction.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Replaces BB Terminator with one that only contains Chunk BBs
|
||||
static void replaceBranchTerminator(BasicBlock &BB,
|
||||
std::set<BasicBlock *> BBsToKeep) {
|
||||
auto Term = BB.getTerminator();
|
||||
std::vector<BasicBlock *> ChunkSucessors;
|
||||
for (auto Succ : successors(&BB))
|
||||
if (BBsToKeep.count(Succ))
|
||||
ChunkSucessors.push_back(Succ);
|
||||
|
||||
// BB only references Chunk BBs
|
||||
if (ChunkSucessors.size() == Term->getNumSuccessors())
|
||||
return;
|
||||
|
||||
bool IsBranch = isa<BranchInst>(Term);
|
||||
Value *Address = nullptr;
|
||||
if (auto IndBI = dyn_cast<IndirectBrInst>(Term))
|
||||
Address = IndBI->getAddress();
|
||||
|
||||
Term->eraseFromParent();
|
||||
|
||||
if (ChunkSucessors.empty()) {
|
||||
ReturnInst::Create(BB.getContext(), nullptr, &BB);
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBranch)
|
||||
BranchInst::Create(ChunkSucessors[0], &BB);
|
||||
|
||||
if (Address) {
|
||||
auto NewIndBI =
|
||||
IndirectBrInst::Create(Address, ChunkSucessors.size(), &BB);
|
||||
for (auto Dest : ChunkSucessors)
|
||||
NewIndBI->addDestination(Dest);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes uninteresting BBs from switch, if the default case ends up being
|
||||
/// uninteresting, the switch is replaced with a void return (since it has to be
|
||||
/// replace with something)
|
||||
static void removeUninterestingBBsFromSwitch(SwitchInst &SwInst,
|
||||
std::set<BasicBlock *> BBsToKeep) {
|
||||
if (!BBsToKeep.count(SwInst.getDefaultDest())) {
|
||||
ReturnInst::Create(SwInst.getContext(), nullptr, SwInst.getParent());
|
||||
SwInst.eraseFromParent();
|
||||
} else
|
||||
for (int I = 0, E = SwInst.getNumCases(); I != E; ++I) {
|
||||
auto Case = SwInst.case_begin() + I;
|
||||
if (!BBsToKeep.count(Case->getCaseSuccessor())) {
|
||||
SwInst.removeCase(Case);
|
||||
--I;
|
||||
--E;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes out-of-chunk arguments from functions, and modifies their calls
|
||||
/// accordingly. It also removes allocations of out-of-chunk arguments.
|
||||
static void extractBasicBlocksFromModule(std::vector<Chunk> ChunksToKeep,
|
||||
Module *Program) {
|
||||
int I = 0, BBCount = 0;
|
||||
std::set<BasicBlock *> BBsToKeep;
|
||||
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F)
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(++BBCount))
|
||||
BBsToKeep.insert(&BB);
|
||||
if (ChunksToKeep[I].end == BBCount)
|
||||
++I;
|
||||
}
|
||||
|
||||
std::vector<BasicBlock *> BBsToDelete;
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F) {
|
||||
if (!BBsToKeep.count(&BB)) {
|
||||
BBsToDelete.push_back(&BB);
|
||||
// Remove out-of-chunk BB from successor phi nodes
|
||||
for (auto *Succ : successors(&BB))
|
||||
Succ->removePredecessor(&BB);
|
||||
}
|
||||
}
|
||||
|
||||
// Replace terminators that reference out-of-chunk BBs
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F) {
|
||||
if (auto *SwInst = dyn_cast<SwitchInst>(BB.getTerminator()))
|
||||
removeUninterestingBBsFromSwitch(*SwInst, BBsToKeep);
|
||||
else
|
||||
replaceBranchTerminator(BB, BBsToKeep);
|
||||
}
|
||||
|
||||
// Replace out-of-chunk switch uses
|
||||
for (auto &BB : BBsToDelete) {
|
||||
// Instructions might be referenced in other BBs
|
||||
for (auto &I : *BB)
|
||||
I.replaceAllUsesWith(UndefValue::get(I.getType()));
|
||||
BB->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
/// Counts the amount of basic blocks and prints their name & respective index
|
||||
static int countBasicBlocks(Module *Program) {
|
||||
// TODO: Silence index with --quiet flag
|
||||
outs() << "----------------------------\n";
|
||||
int BBCount = 0;
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F) {
|
||||
if (BB.hasName())
|
||||
outs() << "\t" << ++BBCount << ": " << BB.getName() << "\n";
|
||||
else
|
||||
outs() << "\t" << ++BBCount << ": Unnamed\n";
|
||||
}
|
||||
|
||||
return BBCount;
|
||||
}
|
||||
|
||||
void llvm::reduceBasicBlocksDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Basic Blocks...\n";
|
||||
int BBCount = countBasicBlocks(Test.getProgram());
|
||||
runDeltaPass(Test, BBCount, extractBasicBlocksFromModule);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceBasicBlocksDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
//===- ReduceFunctions.cpp - Specialized Delta Pass -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce functions (and any instruction that calls it) in the provided
|
||||
// Module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceFunctions.h"
|
||||
#include "Delta.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Removes all the Defined Functions (as well as their calls)
|
||||
/// that aren't inside any of the desired Chunks.
|
||||
static void extractFunctionsFromModule(const std::vector<Chunk> &ChunksToKeep,
|
||||
Module *Program) {
|
||||
// Get functions inside desired chunks
|
||||
std::set<Function *> FuncsToKeep;
|
||||
int I = 0, FunctionCount = 0;
|
||||
for (auto &F : *Program)
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(++FunctionCount))
|
||||
FuncsToKeep.insert(&F);
|
||||
if (FunctionCount == ChunksToKeep[I].end)
|
||||
++I;
|
||||
}
|
||||
|
||||
// Delete out-of-chunk functions, and replace their calls with undef
|
||||
std::vector<Function *> FuncsToRemove;
|
||||
SetVector<CallInst *> CallsToRemove;
|
||||
for (auto &F : *Program)
|
||||
if (!FuncsToKeep.count(&F)) {
|
||||
for (auto U : F.users())
|
||||
if (auto *Call = dyn_cast<CallInst>(U)) {
|
||||
Call->replaceAllUsesWith(UndefValue::get(Call->getType()));
|
||||
CallsToRemove.insert(Call);
|
||||
}
|
||||
F.replaceAllUsesWith(UndefValue::get(F.getType()));
|
||||
FuncsToRemove.push_back(&F);
|
||||
}
|
||||
|
||||
for (auto *C : CallsToRemove)
|
||||
C->eraseFromParent();
|
||||
|
||||
for (auto *F : FuncsToRemove)
|
||||
F->eraseFromParent();
|
||||
}
|
||||
|
||||
/// Counts the amount of non-declaration functions and prints their
|
||||
/// respective name & index
|
||||
static int countFunctions(Module *Program) {
|
||||
// TODO: Silence index with --quiet flag
|
||||
errs() << "----------------------------\n";
|
||||
errs() << "Function Index Reference:\n";
|
||||
int FunctionCount = 0;
|
||||
for (auto &F : *Program)
|
||||
errs() << "\t" << ++FunctionCount << ": " << F.getName() << "\n";
|
||||
|
||||
errs() << "----------------------------\n";
|
||||
return FunctionCount;
|
||||
}
|
||||
|
||||
void llvm::reduceFunctionsDeltaPass(TestRunner &Test) {
|
||||
errs() << "*** Reducing Functions...\n";
|
||||
int Functions = countFunctions(Test.getProgram());
|
||||
runDeltaPass(Test, Functions, extractFunctionsFromModule);
|
||||
errs() << "----------------------------\n";
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
//===- ReduceFunctions.h - Specialized Delta Pass -------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce functions (and any instruction that calls it) in the provided
|
||||
// Module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceFunctionsDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
//===- ReduceGlobalVars.cpp - Specialized Delta Pass ----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce initialized Global Variables in the provided Module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceGlobalVars.h"
|
||||
#include <set>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Removes all the Initialized GVs that aren't inside the desired Chunks.
|
||||
static void extractGVsFromModule(std::vector<Chunk> ChunksToKeep,
|
||||
Module *Program) {
|
||||
// Get GVs inside desired chunks
|
||||
std::set<GlobalVariable *> GVsToKeep;
|
||||
int I = 0, GVCount = 0;
|
||||
for (auto &GV : Program->globals())
|
||||
if (GV.hasInitializer() && I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(++GVCount))
|
||||
GVsToKeep.insert(&GV);
|
||||
if (GVCount == ChunksToKeep[I].end)
|
||||
++I;
|
||||
}
|
||||
|
||||
// Delete out-of-chunk GVs and their uses
|
||||
std::vector<GlobalVariable *> ToRemove;
|
||||
std::vector<Instruction *> InstToRemove;
|
||||
for (auto &GV : Program->globals())
|
||||
if (GV.hasInitializer() && !GVsToKeep.count(&GV)) {
|
||||
for (auto U : GV.users())
|
||||
if (auto *Inst = dyn_cast<Instruction>(U))
|
||||
InstToRemove.push_back(Inst);
|
||||
|
||||
GV.replaceAllUsesWith(UndefValue::get(GV.getType()));
|
||||
ToRemove.push_back(&GV);
|
||||
}
|
||||
|
||||
// Delete Instruction uses of unwanted GVs
|
||||
for (auto *Inst : InstToRemove) {
|
||||
Inst->replaceAllUsesWith(UndefValue::get(Inst->getType()));
|
||||
Inst->eraseFromParent();
|
||||
}
|
||||
|
||||
for (auto *GV : ToRemove)
|
||||
GV->eraseFromParent();
|
||||
}
|
||||
|
||||
/// Counts the amount of initialized GVs and displays their
|
||||
/// respective name & index
|
||||
static int countGVs(Module *Program) {
|
||||
// TODO: Silence index with --quiet flag
|
||||
outs() << "----------------------------\n";
|
||||
outs() << "GlobalVariable Index Reference:\n";
|
||||
int GVCount = 0;
|
||||
for (auto &GV : Program->globals())
|
||||
if (GV.hasInitializer())
|
||||
outs() << "\t" << ++GVCount << ": " << GV.getName() << "\n";
|
||||
outs() << "----------------------------\n";
|
||||
return GVCount;
|
||||
}
|
||||
|
||||
void llvm::reduceGlobalsDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing GVs...\n";
|
||||
int GVCount = countGVs(Test.getProgram());
|
||||
runDeltaPass(Test, GVCount, extractGVsFromModule);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
//===- ReduceGlobalVars.h - Specialized Delta Pass ------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce initialized Global Variables in the provided Module.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceGlobalsDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
//===- ReduceArguments.cpp - Specialized Delta Pass -----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceInstructions.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Removes out-of-chunk arguments from functions, and modifies their calls
|
||||
/// accordingly. It also removes allocations of out-of-chunk arguments.
|
||||
static void extractInstrFromModule(std::vector<Chunk> ChunksToKeep,
|
||||
Module *Program) {
|
||||
int I = 0, InstCount = 0;
|
||||
std::set<Instruction *> InstToKeep;
|
||||
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F)
|
||||
for (auto &Inst : BB)
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(++InstCount))
|
||||
InstToKeep.insert(&Inst);
|
||||
if (ChunksToKeep[I].end == InstCount)
|
||||
++I;
|
||||
}
|
||||
|
||||
std::vector<Instruction *> InstToDelete;
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F)
|
||||
for (auto &Inst : BB)
|
||||
if (!InstToKeep.count(&Inst)) {
|
||||
Inst.replaceAllUsesWith(UndefValue::get(Inst.getType()));
|
||||
InstToDelete.push_back(&Inst);
|
||||
}
|
||||
|
||||
for (auto &I : InstToDelete)
|
||||
I->eraseFromParent();
|
||||
}
|
||||
|
||||
/// Counts the amount of basic blocks and prints their name & respective index
|
||||
static unsigned countInstructions(Module *Program) {
|
||||
// TODO: Silence index with --quiet flag
|
||||
outs() << "----------------------------\n";
|
||||
int InstCount = 0;
|
||||
for (auto &F : *Program)
|
||||
for (auto &BB : F)
|
||||
InstCount += BB.getInstList().size();
|
||||
outs() << "Number of instructions: " << InstCount << "\n";
|
||||
|
||||
return InstCount;
|
||||
}
|
||||
|
||||
void llvm::reduceInstructionsDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Insructions...\n";
|
||||
unsigned InstCount = countInstructions(Test.getProgram());
|
||||
runDeltaPass(Test, InstCount, extractInstrFromModule);
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
//===- ReduceArguments.h - Specialized Delta Pass -------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements a function which calls the Generic Delta pass in order
|
||||
// to reduce uninteresting Arguments from defined functions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Delta.h"
|
||||
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
|
||||
#include "llvm/Transforms/Utils/Cloning.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceInstructionsDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,138 +0,0 @@
|
|||
//===- ReduceMetadata.cpp - Specialized Delta Pass ------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements two functions used by the Generic Delta Debugging
|
||||
// Algorithm, which are used to reduce Metadata nodes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ReduceMetadata.h"
|
||||
#include "Delta.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
/// Adds all Unnamed Metadata Nodes that are inside desired Chunks to set
|
||||
template <class T>
|
||||
static void getChunkMetadataNodes(T &MDUser, int &I,
|
||||
const std::vector<Chunk> &ChunksToKeep,
|
||||
std::set<MDNode *> &SeenNodes,
|
||||
std::set<MDNode *> &NodesToKeep) {
|
||||
SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
|
||||
MDUser.getAllMetadata(MDs);
|
||||
for (auto &MD : MDs) {
|
||||
SeenNodes.insert(MD.second);
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (ChunksToKeep[I].contains(SeenNodes.size()))
|
||||
NodesToKeep.insert(MD.second);
|
||||
if (ChunksToKeep[I].end == (int)SeenNodes.size())
|
||||
++I;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Erases out-of-chunk unnamed metadata nodes from its user
|
||||
template <class T>
|
||||
static void eraseMetadataIfOutsideChunk(T &MDUser,
|
||||
const std::set<MDNode *> &NodesToKeep) {
|
||||
SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
|
||||
MDUser.getAllMetadata(MDs);
|
||||
for (int I = 0, E = MDs.size(); I != E; ++I)
|
||||
if (!NodesToKeep.count(MDs[I].second))
|
||||
MDUser.setMetadata(I, NULL);
|
||||
}
|
||||
|
||||
/// Removes all the Named and Unnamed Metadata Nodes, as well as any debug
|
||||
/// functions that aren't inside the desired Chunks.
|
||||
static void extractMetadataFromModule(const std::vector<Chunk> &ChunksToKeep,
|
||||
Module *Program) {
|
||||
std::set<MDNode *> SeenNodes;
|
||||
std::set<MDNode *> NodesToKeep;
|
||||
int I = 0;
|
||||
|
||||
// Add chunk MDNodes used by GVs, Functions, and Instructions to set
|
||||
for (auto &GV : Program->globals())
|
||||
getChunkMetadataNodes(GV, I, ChunksToKeep, SeenNodes, NodesToKeep);
|
||||
|
||||
for (auto &F : *Program) {
|
||||
getChunkMetadataNodes(F, I, ChunksToKeep, SeenNodes, NodesToKeep);
|
||||
for (auto &BB : F)
|
||||
for (auto &Inst : BB)
|
||||
getChunkMetadataNodes(Inst, I, ChunksToKeep, SeenNodes, NodesToKeep);
|
||||
}
|
||||
|
||||
// Once more, go over metadata nodes, but deleting the ones outside chunks
|
||||
for (auto &GV : Program->globals())
|
||||
eraseMetadataIfOutsideChunk(GV, NodesToKeep);
|
||||
|
||||
for (auto &F : *Program) {
|
||||
eraseMetadataIfOutsideChunk(F, NodesToKeep);
|
||||
for (auto &BB : F)
|
||||
for (auto &Inst : BB)
|
||||
eraseMetadataIfOutsideChunk(Inst, NodesToKeep);
|
||||
}
|
||||
|
||||
|
||||
// Get out-of-chunk Named metadata nodes
|
||||
unsigned MetadataCount = SeenNodes.size();
|
||||
std::vector<NamedMDNode *> NamedNodesToDelete;
|
||||
for (auto &MD : Program->named_metadata()) {
|
||||
if (I < (int)ChunksToKeep.size()) {
|
||||
if (!ChunksToKeep[I].contains(++MetadataCount))
|
||||
NamedNodesToDelete.push_back(&MD);
|
||||
if (ChunksToKeep[I].end == (int)SeenNodes.size())
|
||||
++I;
|
||||
} else
|
||||
NamedNodesToDelete.push_back(&MD);
|
||||
}
|
||||
|
||||
for (auto *NN : NamedNodesToDelete) {
|
||||
for (int I = 0, E = NN->getNumOperands(); I != E; ++I)
|
||||
NN->setOperand(I, NULL);
|
||||
NN->eraseFromParent();
|
||||
}
|
||||
}
|
||||
|
||||
// Gets unnamed metadata nodes used by a given instruction/GV/function and adds
|
||||
// them to the set of seen nodes
|
||||
template <class T>
|
||||
static void addMetadataToSet(T &MDUser, std::set<MDNode *> &UnnamedNodes) {
|
||||
SmallVector<std::pair<unsigned, MDNode *>, 4> MDs;
|
||||
MDUser.getAllMetadata(MDs);
|
||||
for (auto &MD : MDs)
|
||||
UnnamedNodes.insert(MD.second);
|
||||
}
|
||||
|
||||
/// Returns the amount of Named and Unnamed Metadata Nodes
|
||||
static int countMetadataTargets(Module *Program) {
|
||||
std::set<MDNode *> UnnamedNodes;
|
||||
int NamedMetadataNodes = Program->named_metadata_size();
|
||||
|
||||
// Get metadata nodes used by globals
|
||||
for (auto &GV : Program->globals())
|
||||
addMetadataToSet(GV, UnnamedNodes);
|
||||
|
||||
// Do the same for nodes used by functions & instructions
|
||||
for (auto &F : *Program) {
|
||||
addMetadataToSet(F, UnnamedNodes);
|
||||
for (auto &BB : F)
|
||||
for (auto &I : BB)
|
||||
addMetadataToSet(I, UnnamedNodes);
|
||||
}
|
||||
|
||||
return UnnamedNodes.size() + NamedMetadataNodes;
|
||||
}
|
||||
|
||||
void llvm::reduceMetadataDeltaPass(TestRunner &Test) {
|
||||
outs() << "*** Reducing Metadata...\n";
|
||||
int MDCount = countMetadataTargets(Test.getProgram());
|
||||
runDeltaPass(Test, MDCount, extractMetadataFromModule);
|
||||
outs() << "----------------------------\n";
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
//===- ReduceMetadata.h - Specialized Delta Pass ------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements two functions used by the Generic Delta Debugging
|
||||
// Algorithm, which are used to reduce Metadata nodes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "TestRunner.h"
|
||||
|
||||
namespace llvm {
|
||||
void reduceMetadataDeltaPass(TestRunner &Test);
|
||||
} // namespace llvm
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
//===- llvm-reduce.cpp - The LLVM Delta Reduction utility -----------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This program tries to reduce an IR test case for a given interesting-ness
|
||||
// test. It runs multiple delta debugging passes in order to minimize the input
|
||||
// file. It's worth noting that this is a part of the bugpoint redesign
|
||||
// proposal, and thus a *temporary* tool that will eventually be integrated
|
||||
// into the bugpoint tool itself.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DeltaManager.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/IR/Verifier.h"
|
||||
#include "llvm/IRReader/IRReader.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/InitLLVM.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <system_error>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
|
||||
static cl::opt<bool> Version("v", cl::desc("Alias for -version"), cl::Hidden);
|
||||
|
||||
static cl::opt<std::string> InputFilename(cl::Positional, cl::Required,
|
||||
cl::desc("<input llvm ll/bc file>"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
TestFilename("test", cl::Required,
|
||||
cl::desc("Name of the interesting-ness test to be run"));
|
||||
|
||||
static cl::list<std::string>
|
||||
TestArguments("test-arg", cl::ZeroOrMore,
|
||||
cl::desc("Arguments passed onto the interesting-ness test"));
|
||||
|
||||
static cl::opt<std::string>
|
||||
OutputFilename("output",
|
||||
cl::desc("Specify the output file. default: reduced.ll"));
|
||||
static cl::alias OutputFileAlias("o", cl::desc("Alias for -output"),
|
||||
cl::aliasopt(OutputFilename));
|
||||
|
||||
static cl::opt<bool>
|
||||
ReplaceInput("in-place",
|
||||
cl::desc("WARNING: This option will replace your input file"
|
||||
"with the reduced version!"));
|
||||
|
||||
// Parses IR into a Module and verifies it
|
||||
static std::unique_ptr<Module> parseInputFile(StringRef Filename,
|
||||
LLVMContext &Ctxt) {
|
||||
SMDiagnostic Err;
|
||||
std::unique_ptr<Module> Result = parseIRFile(Filename, Err, Ctxt);
|
||||
if (!Result) {
|
||||
Err.print("llvm-reduce", errs());
|
||||
return Result;
|
||||
}
|
||||
|
||||
if (verifyModule(*Result, &errs())) {
|
||||
errs() << "Error: " << Filename << " - input module is broken!\n";
|
||||
return std::unique_ptr<Module>();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
InitLLVM X(argc, argv);
|
||||
|
||||
cl::ParseCommandLineOptions(argc, argv, "LLVM automatic testcase reducer.\n");
|
||||
|
||||
LLVMContext Context;
|
||||
std::unique_ptr<Module> OriginalProgram =
|
||||
parseInputFile(InputFilename, Context);
|
||||
|
||||
// Initialize test environment
|
||||
TestRunner Tester(TestFilename, TestArguments);
|
||||
Tester.setProgram(std::move(OriginalProgram));
|
||||
|
||||
// Try to reduce code
|
||||
runDeltaPasses(Tester);
|
||||
|
||||
if (!Tester.getProgram()) {
|
||||
errs() << "\nCouldnt reduce input :/\n";
|
||||
} else {
|
||||
// Print reduced file to STDOUT
|
||||
if (OutputFilename == "-")
|
||||
Tester.getProgram()->print(outs(), nullptr);
|
||||
else {
|
||||
if (ReplaceInput) // In-place
|
||||
OutputFilename = InputFilename.c_str();
|
||||
else if (OutputFilename.empty())
|
||||
OutputFilename = "reduced.ll";
|
||||
|
||||
std::error_code EC;
|
||||
raw_fd_ostream Out(OutputFilename, EC);
|
||||
if (EC) {
|
||||
errs() << "Error opening output file: " << EC.message() << "!\n";
|
||||
exit(1);
|
||||
}
|
||||
Tester.getProgram()->print(Out, /*AnnotationWriter=*/nullptr);
|
||||
errs() << "\nDone reducing! Reduced testcase: " << OutputFilename << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Analysis
|
||||
Support
|
||||
)
|
||||
add_llvm_fuzzer(vfabi-demangler-fuzzer
|
||||
vfabi-demangler-fuzzer.cpp
|
||||
)
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
//===-- vfabi-demangler-fuzzer.cpp - Fuzzer VFABI using lib/Fuzzer ------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Build tool to fuzz the demangler for the vector function ABI names.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Analysis/VectorUtils.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
const StringRef MangledName((const char *)Data, Size);
|
||||
const auto Info = VFABI::tryDemangleForVFABI(MangledName);
|
||||
|
||||
// Do not optimize away the return value. Inspired by
|
||||
// https://github.com/google/benchmark/blob/master/include/benchmark/benchmark.h#L307-L345
|
||||
asm volatile("" : : "r,m"(Info) : "memory");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
set(LLVM_LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
|
||||
llvm_add_library(LLVMTableGenGlobalISel STATIC DISABLE_LLVM_LINK_LLVM_DYLIB
|
||||
CodeExpander.cpp
|
||||
)
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
import re, sys
|
||||
|
||||
def fix_string(s):
|
||||
TYPE = re.compile('\s*(i[0-9]+|float|double|x86_fp80|fp128|ppc_fp128|\[\[.*?\]\]|\[2 x \[\[[A-Z_0-9]+\]\]\]|<.*?>|{.*?}|\[[0-9]+ x .*?\]|%["a-z:A-Z0-9._]+({{.*?}})?|%{{.*?}}|{{.*?}}|\[\[.*?\]\])(\s*(\*|addrspace\(.*?\)|dereferenceable\(.*?\)|byval\(.*?\)|sret|zeroext|inreg|returned|signext|nocapture|align \d+|swiftself|swifterror|readonly|noalias|inalloca|nocapture))*\s*')
|
||||
|
||||
counter = 0
|
||||
if 'i32{{.*}}' in s:
|
||||
counter = 1
|
||||
|
||||
at_pos = s.find('@')
|
||||
if at_pos == -1:
|
||||
at_pos = 0
|
||||
|
||||
annoying_pos = s.find('{{[^(]+}}')
|
||||
if annoying_pos != -1:
|
||||
at_pos = annoying_pos + 9
|
||||
|
||||
paren_pos = s.find('(', at_pos)
|
||||
if paren_pos == -1:
|
||||
return s
|
||||
|
||||
res = s[:paren_pos+1]
|
||||
s = s[paren_pos+1:]
|
||||
|
||||
m = TYPE.match(s)
|
||||
while m:
|
||||
res += m.group()
|
||||
s = s[m.end():]
|
||||
if s.startswith(',') or s.startswith(')'):
|
||||
res += f' %{counter}'
|
||||
counter += 1
|
||||
|
||||
next_arg = s.find(',')
|
||||
if next_arg == -1:
|
||||
break
|
||||
|
||||
res += s[:next_arg+1]
|
||||
s = s[next_arg+1:]
|
||||
m = TYPE.match(s)
|
||||
|
||||
return res+s
|
||||
|
||||
def process_file(contents):
|
||||
PREFIX = re.compile(r'check-prefix(es)?(=|\s+)([a-zA-Z0-9,]+)')
|
||||
check_prefixes = ['CHECK']
|
||||
result = ''
|
||||
for line in contents.split('\n'):
|
||||
if 'FileCheck' in line:
|
||||
m = PREFIX.search(line)
|
||||
if m:
|
||||
check_prefixes.extend(m.group(3).split(','))
|
||||
|
||||
found_check = False
|
||||
for prefix in check_prefixes:
|
||||
if prefix in line:
|
||||
found_check = True
|
||||
break
|
||||
|
||||
if not found_check or 'define' not in line:
|
||||
result += line + '\n'
|
||||
continue
|
||||
|
||||
# We have a check for a function definition. Number the args.
|
||||
line = fix_string(line)
|
||||
result += line + '\n'
|
||||
return result
|
||||
|
||||
def main():
|
||||
print(f'Processing {sys.argv[1]}')
|
||||
f = open(sys.argv[1])
|
||||
content = f.read()
|
||||
f.close()
|
||||
|
||||
content = process_file(content)
|
||||
|
||||
f = open(sys.argv[1], 'w')
|
||||
f.write(content)
|
||||
f.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
if (LLVM_BUILD_UTILS AND LLVM_BUILD_TOOLS)
|
||||
add_custom_command(
|
||||
OUTPUT ${LLVM_TOOLS_BINARY_DIR}/llvm-locstats
|
||||
DEPENDS ${LLVM_MAIN_SRC_DIR}/utils/llvm-locstats/llvm-locstats.py
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${LLVM_MAIN_SRC_DIR}/utils/llvm-locstats/llvm-locstats.py ${LLVM_TOOLS_BINARY_DIR}/llvm-locstats
|
||||
COMMENT "Copying llvm-locstats into ${LLVM_TOOLS_BINARY_DIR}"
|
||||
)
|
||||
add_custom_target(llvm-locstats ALL
|
||||
DEPENDS ${LLVM_TOOLS_BINARY_DIR}/llvm-locstats
|
||||
)
|
||||
set_target_properties(llvm-locstats PROPERTIES FOLDER "Tools")
|
||||
endif()
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# This is a tool that works like debug location coverage calculator.
|
||||
# It parses the llvm-dwarfdump --statistics output by reporting it
|
||||
# in a more human readable way.
|
||||
#
|
||||
|
||||
from __future__ import print_function
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from json import loads
|
||||
from math import ceil
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
def coverage_buckets():
|
||||
yield '0%'
|
||||
yield '1-9%'
|
||||
for start in range(10, 91, 10):
|
||||
yield '{0}-{1}%'.format(start, start + 9)
|
||||
yield '100%'
|
||||
|
||||
def locstats_output(
|
||||
variables_total,
|
||||
variables_total_locstats,
|
||||
variables_with_loc,
|
||||
scope_bytes_covered,
|
||||
scope_bytes_from_first_def,
|
||||
variables_coverage_map
|
||||
):
|
||||
|
||||
pc_ranges_covered = int(ceil(scope_bytes_covered * 100.0)
|
||||
/ scope_bytes_from_first_def)
|
||||
variables_coverage_per_map = {}
|
||||
for cov_bucket in coverage_buckets():
|
||||
variables_coverage_per_map[cov_bucket] = \
|
||||
int(ceil(variables_coverage_map[cov_bucket] * 100.0) \
|
||||
/ variables_total_locstats)
|
||||
|
||||
print (' =================================================')
|
||||
print (' Debug Location Statistics ')
|
||||
print (' =================================================')
|
||||
print (' cov% samples percentage(~) ')
|
||||
print (' -------------------------------------------------')
|
||||
for cov_bucket in coverage_buckets():
|
||||
print (' {0:6} {1:8d} {2:3d}%'. \
|
||||
format(cov_bucket, variables_coverage_map[cov_bucket], \
|
||||
variables_coverage_per_map[cov_bucket]))
|
||||
print (' =================================================')
|
||||
print (' -the number of debug variables processed: ' \
|
||||
+ str(variables_total_locstats))
|
||||
print (' -PC ranges covered: ' + str(pc_ranges_covered) + '%')
|
||||
|
||||
# Only if we are processing all the variables output the total
|
||||
# availability.
|
||||
if variables_total and variables_with_loc:
|
||||
total_availability = int(ceil(variables_with_loc * 100.0) \
|
||||
/ variables_total)
|
||||
print (' -------------------------------------------------')
|
||||
print (' -total availability: ' + str(total_availability) + '%')
|
||||
print (' =================================================')
|
||||
|
||||
def parse_program_args(parser):
|
||||
parser.add_argument('-only-variables', action='store_true',
|
||||
default=False,
|
||||
help='calculate the location statistics only for '
|
||||
'local variables'
|
||||
)
|
||||
parser.add_argument('-only-formal-parameters', action='store_true',
|
||||
default=False,
|
||||
help='calculate the location statistics only for '
|
||||
'formal parameters'
|
||||
)
|
||||
parser.add_argument('-ignore-debug-entry-values', action='store_true',
|
||||
default=False,
|
||||
help='ignore the location statistics on locations with '
|
||||
'entry values'
|
||||
)
|
||||
parser.add_argument('file_name', type=str, help='file to process')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def Main():
|
||||
parser = argparse.ArgumentParser()
|
||||
results = parse_program_args(parser)
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print ('error: Too few arguments.')
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
if results.only_variables and results.only_formal_parameters:
|
||||
print ('error: Please use just one only* option.')
|
||||
parser.print_help()
|
||||
sys.exit(1)
|
||||
|
||||
# These will be different due to different options enabled.
|
||||
variables_total = None
|
||||
variables_total_locstats = None
|
||||
variables_with_loc = None
|
||||
variables_scope_bytes_covered = None
|
||||
variables_scope_bytes_from_first_def = None
|
||||
variables_scope_bytes_entry_values = None
|
||||
variables_coverage_map = {}
|
||||
binary = results.file_name
|
||||
|
||||
# Get the directory of the LLVM tools.
|
||||
llvm_dwarfdump_cmd = os.path.join(os.path.dirname(__file__), \
|
||||
"llvm-dwarfdump")
|
||||
# The statistics llvm-dwarfdump option.
|
||||
llvm_dwarfdump_stats_opt = "--statistics"
|
||||
|
||||
subproc = Popen([llvm_dwarfdump_cmd, llvm_dwarfdump_stats_opt, binary], \
|
||||
stdin=PIPE, stdout=PIPE, stderr=PIPE, \
|
||||
universal_newlines = True)
|
||||
cmd_stdout, cmd_stderr = subproc.communicate()
|
||||
|
||||
# Get the JSON and parse it.
|
||||
json_parsed = None
|
||||
|
||||
try:
|
||||
json_parsed = loads(cmd_stdout)
|
||||
except:
|
||||
print ('error: No valid llvm-dwarfdump statistics found.')
|
||||
sys.exit(1)
|
||||
|
||||
if results.only_variables:
|
||||
# Read the JSON only for local variables.
|
||||
variables_total_locstats = \
|
||||
json_parsed['total vars procesed by location statistics']
|
||||
variables_scope_bytes_covered = \
|
||||
json_parsed['vars scope bytes covered']
|
||||
variables_scope_bytes_from_first_def = \
|
||||
json_parsed['vars scope bytes total']
|
||||
if not results.ignore_debug_entry_values:
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = "vars with {} of its scope covered".format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
else:
|
||||
variables_scope_bytes_entry_values = \
|
||||
json_parsed['vars entry value scope bytes covered']
|
||||
variables_scope_bytes_covered = variables_scope_bytes_covered \
|
||||
- variables_scope_bytes_entry_values
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = \
|
||||
"vars (excluding the debug entry values) " \
|
||||
"with {} of its scope covered".format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
elif results.only_formal_parameters:
|
||||
# Read the JSON only for formal parameters.
|
||||
variables_total_locstats = \
|
||||
json_parsed['total params procesed by location statistics']
|
||||
variables_scope_bytes_covered = \
|
||||
json_parsed['formal params scope bytes covered']
|
||||
variables_scope_bytes_from_first_def = \
|
||||
json_parsed['formal params scope bytes total']
|
||||
if not results.ignore_debug_entry_values:
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = "params with {} of its scope covered".format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
else:
|
||||
variables_scope_bytes_entry_values = \
|
||||
json_parsed['formal params entry value scope bytes covered']
|
||||
variables_scope_bytes_covered = variables_scope_bytes_covered \
|
||||
- variables_scope_bytes_entry_values
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = \
|
||||
"params (excluding the debug entry values) " \
|
||||
"with {} of its scope covered".format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
else:
|
||||
# Read the JSON for both local variables and formal parameters.
|
||||
variables_total = \
|
||||
json_parsed['source variables']
|
||||
variables_with_loc = json_parsed['variables with location']
|
||||
variables_total_locstats = \
|
||||
json_parsed['total variables procesed by location statistics']
|
||||
variables_scope_bytes_covered = \
|
||||
json_parsed['scope bytes covered']
|
||||
variables_scope_bytes_from_first_def = \
|
||||
json_parsed['scope bytes total']
|
||||
if not results.ignore_debug_entry_values:
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = "variables with {} of its scope covered". \
|
||||
format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
else:
|
||||
variables_scope_bytes_entry_values = \
|
||||
json_parsed['entry value scope bytes covered']
|
||||
variables_scope_bytes_covered = variables_scope_bytes_covered \
|
||||
- variables_scope_bytes_entry_values
|
||||
for cov_bucket in coverage_buckets():
|
||||
cov_category = "variables (excluding the debug entry values) " \
|
||||
"with {} of its scope covered". format(cov_bucket)
|
||||
variables_coverage_map[cov_bucket] = json_parsed[cov_category]
|
||||
|
||||
# Pretty print collected info.
|
||||
locstats_output(
|
||||
variables_total,
|
||||
variables_total_locstats,
|
||||
variables_with_loc,
|
||||
variables_scope_bytes_covered,
|
||||
variables_scope_bytes_from_first_def,
|
||||
variables_coverage_map
|
||||
)
|
||||
|
||||
if __name__ == '__main__':
|
||||
Main()
|
||||
sys.exit(0)
|
||||
Loading…
Reference in a new issue