forked from OSchip/llvm-project
IR: Module summary representation for type identifiers; summary test scaffolding for lowertypetests.
Set up basic YAML I/O support for module summaries, plumb the summary into the pass and add a few command line flags to test YAML I/O support. Bitcode support to come separately, as will the code in LowerTypeTests that actually uses the summary. Also add a couple of tests that pass by virtue of the pass doing nothing with the summary (which happens to be the correct thing to do for those tests). Differential Revision: https://reviews.llvm.org/D28041 llvm-svn: 291069
This commit is contained in:
parent
4ae2e0c386
commit
b2ce2b6805
|
@ -28,6 +28,10 @@
|
|||
|
||||
namespace llvm {
|
||||
|
||||
namespace yaml {
|
||||
template <typename T> struct MappingTraits;
|
||||
}
|
||||
|
||||
/// \brief Class to accumulate and hold information about a callee.
|
||||
struct CalleeInfo {
|
||||
enum class HotnessType : uint8_t { Unknown = 0, Cold = 1, None = 2, Hot = 3 };
|
||||
|
@ -330,6 +334,30 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct TypeTestResolution {
|
||||
/// Specifies which kind of type check we should emit for this byte array.
|
||||
/// See http://clang.llvm.org/docs/ControlFlowIntegrityDesign.html for full
|
||||
/// details on each kind of check; the enumerators are described with
|
||||
/// reference to that document.
|
||||
enum Kind {
|
||||
Unsat, ///< Unsatisfiable type (i.e. no global has this type metadata)
|
||||
ByteArray, ///< Test a byte array (first example)
|
||||
Inline, ///< Inlined bit vector ("Short Inline Bit Vectors")
|
||||
Single, ///< Single element (last example in "Short Inline Bit Vectors")
|
||||
AllOnes, ///< All-ones bit vector ("Eliminating Bit Vector Checks for
|
||||
/// All-Ones Bit Vectors")
|
||||
} TheKind = Unsat;
|
||||
|
||||
/// Range of the size expressed as a bit width. For example, if the size is in
|
||||
/// range [0,256), this number will be 8. This helps generate the most compact
|
||||
/// instruction sequences.
|
||||
unsigned SizeBitWidth = 0;
|
||||
};
|
||||
|
||||
struct TypeIdSummary {
|
||||
TypeTestResolution TTRes;
|
||||
};
|
||||
|
||||
/// 160 bits SHA1
|
||||
typedef std::array<uint32_t, 5> ModuleHash;
|
||||
|
||||
|
@ -370,6 +398,14 @@ private:
|
|||
/// Holds strings for combined index, mapping to the corresponding module ID.
|
||||
ModulePathStringTableTy ModulePathStringTable;
|
||||
|
||||
/// Mapping from type identifiers to summary information for that type
|
||||
/// identifier.
|
||||
// FIXME: Add bitcode read/write support for this field.
|
||||
std::map<std::string, TypeIdSummary> TypeIdMap;
|
||||
|
||||
// YAML I/O support.
|
||||
friend yaml::MappingTraits<ModuleSummaryIndex>;
|
||||
|
||||
public:
|
||||
gvsummary_iterator begin() { return GlobalValueMap.begin(); }
|
||||
const_gvsummary_iterator begin() const { return GlobalValueMap.begin(); }
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
//===-- llvm/ModuleSummaryIndexYAML.h - YAML I/O for summary ----*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_IR_MODULESUMMARYINDEXYAML_H
|
||||
#define LLVM_IR_MODULESUMMARYINDEXYAML_H
|
||||
|
||||
#include "llvm/IR/ModuleSummaryIndex.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
template <> struct ScalarEnumerationTraits<TypeTestResolution::Kind> {
|
||||
static void enumeration(IO &io, TypeTestResolution::Kind &value) {
|
||||
io.enumCase(value, "Unsat", TypeTestResolution::Unsat);
|
||||
io.enumCase(value, "ByteArray", TypeTestResolution::ByteArray);
|
||||
io.enumCase(value, "Inline", TypeTestResolution::Inline);
|
||||
io.enumCase(value, "Single", TypeTestResolution::Single);
|
||||
io.enumCase(value, "AllOnes", TypeTestResolution::AllOnes);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<TypeTestResolution> {
|
||||
static void mapping(IO &io, TypeTestResolution &res) {
|
||||
io.mapRequired("Kind", res.TheKind);
|
||||
io.mapRequired("SizeBitWidth", res.SizeBitWidth);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<TypeIdSummary> {
|
||||
static void mapping(IO &io, TypeIdSummary& summary) {
|
||||
io.mapRequired("TTRes", summary.TTRes);
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionSummaryYaml {
|
||||
std::vector<uint64_t> TypeTests;
|
||||
};
|
||||
|
||||
} // End yaml namespace
|
||||
} // End llvm namespace
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
template <> struct MappingTraits<FunctionSummaryYaml> {
|
||||
static void mapping(IO &io, FunctionSummaryYaml& summary) {
|
||||
io.mapRequired("TypeTests", summary.TypeTests);
|
||||
}
|
||||
};
|
||||
|
||||
} // End yaml namespace
|
||||
} // End llvm namespace
|
||||
|
||||
LLVM_YAML_IS_STRING_MAP(TypeIdSummary)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionSummaryYaml)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
// FIXME: Add YAML mappings for the rest of the module summary.
|
||||
template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
|
||||
static void inputOne(IO &io, StringRef Key, GlobalValueSummaryMapTy &V) {
|
||||
std::vector<FunctionSummaryYaml> FSums;
|
||||
io.mapRequired(Key.str().c_str(), FSums);
|
||||
uint64_t KeyInt;
|
||||
if (Key.getAsInteger(0, KeyInt)) {
|
||||
io.setError("key not an integer");
|
||||
return;
|
||||
}
|
||||
auto &Elem = V[KeyInt];
|
||||
for (auto &FSum : FSums) {
|
||||
GlobalValueSummary::GVFlags GVFlags(GlobalValue::ExternalLinkage, false,
|
||||
false, false);
|
||||
Elem.push_back(make_unique<FunctionSummary>(
|
||||
GVFlags, 0, ArrayRef<ValueInfo>{},
|
||||
ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests)));
|
||||
}
|
||||
}
|
||||
static void output(IO &io, GlobalValueSummaryMapTy &V) {
|
||||
for (auto &P : V) {
|
||||
std::vector<FunctionSummaryYaml> FSums;
|
||||
for (auto &Sum : P.second) {
|
||||
if (auto *FSum = dyn_cast<FunctionSummary>(Sum.get()))
|
||||
FSums.push_back(FunctionSummaryYaml{FSum->type_tests()});
|
||||
}
|
||||
if (!FSums.empty())
|
||||
io.mapRequired(std::to_string(P.first).c_str(), FSums);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<ModuleSummaryIndex> {
|
||||
static void mapping(IO &io, ModuleSummaryIndex& index) {
|
||||
io.mapRequired("GlobalValueMap", index.GlobalValueMap);
|
||||
io.mapRequired("TypeIdMap", index.TypeIdMap);
|
||||
}
|
||||
};
|
||||
|
||||
} // End yaml namespace
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
|
@ -27,9 +27,12 @@
|
|||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/ModuleSummaryIndexYAML.h"
|
||||
#include "llvm/IR/Operator.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include "llvm/Support/FileSystem.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/Transforms/IPO.h"
|
||||
|
@ -52,6 +55,20 @@ static cl::opt<bool> AvoidReuse(
|
|||
cl::desc("Try to avoid reuse of byte array addresses using aliases"),
|
||||
cl::Hidden, cl::init(true));
|
||||
|
||||
static cl::opt<std::string> ClSummaryAction(
|
||||
"lowertypetests-summary-action",
|
||||
cl::desc("What to do with the summary when running this pass"), cl::Hidden);
|
||||
|
||||
static cl::opt<std::string> ClReadSummary(
|
||||
"lowertypetests-read-summary",
|
||||
cl::desc("Read summary from given YAML file before running pass"),
|
||||
cl::Hidden);
|
||||
|
||||
static cl::opt<std::string> ClWriteSummary(
|
||||
"lowertypetests-write-summary",
|
||||
cl::desc("Write summary to given YAML file after running pass"),
|
||||
cl::Hidden);
|
||||
|
||||
bool BitSetInfo::containsGlobalOffset(uint64_t Offset) const {
|
||||
if (Offset < ByteOffset)
|
||||
return false;
|
||||
|
@ -241,6 +258,9 @@ public:
|
|||
class LowerTypeTestsModule {
|
||||
Module &M;
|
||||
|
||||
// This is for testing purposes only.
|
||||
std::unique_ptr<ModuleSummaryIndex> OwnedSummary;
|
||||
|
||||
bool LinkerSubsectionsViaSymbols;
|
||||
Triple::ArchType Arch;
|
||||
Triple::OSType OS;
|
||||
|
@ -302,6 +322,7 @@ class LowerTypeTestsModule {
|
|||
|
||||
public:
|
||||
LowerTypeTestsModule(Module &M);
|
||||
~LowerTypeTestsModule();
|
||||
bool lower();
|
||||
};
|
||||
|
||||
|
@ -1080,6 +1101,22 @@ void LowerTypeTestsModule::buildBitSetsFromDisjointSet(
|
|||
|
||||
/// Lower all type tests in this module.
|
||||
LowerTypeTestsModule::LowerTypeTestsModule(Module &M) : M(M) {
|
||||
// Handle the command-line summary arguments. This code is for testing
|
||||
// purposes only, so we handle errors directly.
|
||||
if (!ClSummaryAction.empty()) {
|
||||
OwnedSummary = make_unique<ModuleSummaryIndex>();
|
||||
if (!ClReadSummary.empty()) {
|
||||
ExitOnError ExitOnErr("-lowertypetests-read-summary: " + ClReadSummary +
|
||||
": ");
|
||||
auto ReadSummaryFile =
|
||||
ExitOnErr(errorOrToExpected(MemoryBuffer::getFile(ClReadSummary)));
|
||||
|
||||
yaml::Input In(ReadSummaryFile->getBuffer());
|
||||
In >> *OwnedSummary;
|
||||
ExitOnErr(errorCodeToError(In.error()));
|
||||
}
|
||||
}
|
||||
|
||||
Triple TargetTriple(M.getTargetTriple());
|
||||
LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX();
|
||||
Arch = TargetTriple.getArch();
|
||||
|
@ -1087,6 +1124,20 @@ LowerTypeTestsModule::LowerTypeTestsModule(Module &M) : M(M) {
|
|||
ObjectFormat = TargetTriple.getObjectFormat();
|
||||
}
|
||||
|
||||
LowerTypeTestsModule::~LowerTypeTestsModule() {
|
||||
if (ClSummaryAction.empty() || ClWriteSummary.empty())
|
||||
return;
|
||||
|
||||
ExitOnError ExitOnErr("-lowertypetests-write-summary: " + ClWriteSummary +
|
||||
": ");
|
||||
std::error_code EC;
|
||||
raw_fd_ostream OS(ClWriteSummary, EC, sys::fs::F_Text);
|
||||
ExitOnErr(errorCodeToError(EC));
|
||||
|
||||
yaml::Output Out(OS);
|
||||
Out << *OwnedSummary;
|
||||
}
|
||||
|
||||
bool LowerTypeTestsModule::lower() {
|
||||
Function *TypeTestFunc =
|
||||
M.getFunction(Intrinsic::getName(Intrinsic::type_test));
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
GlobalValueMap:
|
||||
42:
|
||||
- TypeTests: [123]
|
||||
TypeIdMap:
|
||||
typeid1:
|
||||
TTRes:
|
||||
Kind: Unsat
|
||||
SizeBitWidth: 0
|
||||
...
|
|
@ -0,0 +1,7 @@
|
|||
; RUN: opt -lowertypetests -lowertypetests-summary-action=export -lowertypetests-write-summary=%t -o /dev/null %s
|
||||
; RUN: FileCheck %s < %t
|
||||
|
||||
; CHECK: ---
|
||||
; CHECK-NEXT: GlobalValueMap:
|
||||
; CHECK-NEXT: TypeIdMap:
|
||||
; CHECK-NEXT: ...
|
|
@ -0,0 +1,24 @@
|
|||
; Test that we correctly import an unsat resolution for type identifier "typeid1".
|
||||
; FIXME: We should not require -O2 to simplify this to return false.
|
||||
; RUN: opt -S -lowertypetests -lowertypetests-summary-action=import -lowertypetests-read-summary=%S/Inputs/import-unsat.yaml -lowertypetests-write-summary=%t -O2 < %s | FileCheck %s
|
||||
; RUN: FileCheck --check-prefix=SUMMARY %s < %t
|
||||
|
||||
; SUMMARY: GlobalValueMap:
|
||||
; SUMMARY-NEXT: 42:
|
||||
; SUMMARY-NEXT: - TypeTests:
|
||||
; SUMMARY-NEXT: - 123
|
||||
; SUMMARY-NEXT: TypeIdMap:
|
||||
; SUMMARY-NEXT: typeid1:
|
||||
; SUMMARY-NEXT: TTRes:
|
||||
; SUMMARY-NEXT: Kind: Unsat
|
||||
; SUMMARY-NEXT: SizeBitWidth: 0
|
||||
|
||||
target datalayout = "e-p:32:32"
|
||||
|
||||
declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
|
||||
|
||||
define i1 @foo(i8* %p) {
|
||||
%x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
|
||||
; CHECK: ret i1 false
|
||||
ret i1 %x
|
||||
}
|
Loading…
Reference in New Issue