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:
Peter Collingbourne 2017-01-05 03:39:00 +00:00
parent 4ae2e0c386
commit b2ce2b6805
6 changed files with 239 additions and 0 deletions

View File

@ -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(); }

View File

@ -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

View File

@ -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));

View File

@ -0,0 +1,10 @@
---
GlobalValueMap:
42:
- TypeTests: [123]
TypeIdMap:
typeid1:
TTRes:
Kind: Unsat
SizeBitWidth: 0
...

View File

@ -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: ...

View File

@ -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
}