Index: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h @@ -28,6 +28,10 @@ namespace llvm { +namespace yaml { +template 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 @@ } }; +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 ModuleHash; @@ -370,6 +398,14 @@ /// 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 TypeIdMap; + + // YAML I/O support. + friend yaml::MappingTraits; + public: gvsummary_iterator begin() { return GlobalValueMap.begin(); } const_gvsummary_iterator begin() const { return GlobalValueMap.begin(); } Index: llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -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 { + 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 { + static void mapping(IO &io, TypeTestResolution &res) { + io.mapRequired("Kind", res.TheKind); + io.mapRequired("SizeBitWidth", res.SizeBitWidth); + } +}; + +template <> struct MappingTraits { + static void mapping(IO &io, TypeIdSummary& summary) { + io.mapRequired("TTRes", summary.TTRes); + } +}; + +struct FunctionSummaryYaml { + std::vector TypeTests; +}; + +} // End yaml namespace +} // End llvm namespace + +LLVM_YAML_IS_SEQUENCE_VECTOR(uint64_t) + +namespace llvm { +namespace yaml { + +template <> struct MappingTraits { + 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 { + static void inputOne(IO &io, StringRef Key, GlobalValueSummaryMapTy &V) { + std::vector 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( + GVFlags, 0, ArrayRef{}, + ArrayRef{}, std::move(FSum.TypeTests))); + } + } + static void output(IO &io, GlobalValueSummaryMapTy &V) { + for (auto &P : V) { + std::vector FSums; + for (auto &Sum : P.second) { + if (auto *FSum = dyn_cast(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 { + static void mapping(IO &io, ModuleSummaryIndex& index) { + io.mapRequired("GlobalValueMap", index.GlobalValueMap); + io.mapRequired("TypeIdMap", index.TypeIdMap); + } +}; + +} // End yaml namespace +} // End llvm namespace + +#endif Index: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp @@ -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 @@ cl::desc("Try to avoid reuse of byte array addresses using aliases"), cl::Hidden, cl::init(true)); +static cl::opt ClSummaryAction( + "lowertypetests-summary-action", + cl::desc("What to do with the summary when running this pass"), cl::Hidden); + +static cl::opt ClReadSummary( + "lowertypetests-read-summary", + cl::desc("Read summary from given YAML file before running pass"), + cl::Hidden); + +static cl::opt 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 @@ class LowerTypeTestsModule { Module &M; + // This is for testing purposes only. + std::unique_ptr OwnedSummary; + bool LinkerSubsectionsViaSymbols; Triple::ArchType Arch; Triple::OSType OS; @@ -302,6 +322,7 @@ public: LowerTypeTestsModule(Module &M); + ~LowerTypeTestsModule(); bool lower(); }; @@ -1080,6 +1101,22 @@ /// 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(); + 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 @@ 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)); Index: llvm/trunk/test/Transforms/LowerTypeTests/Inputs/import-unsat.yaml =================================================================== --- llvm/trunk/test/Transforms/LowerTypeTests/Inputs/import-unsat.yaml +++ llvm/trunk/test/Transforms/LowerTypeTests/Inputs/import-unsat.yaml @@ -0,0 +1,10 @@ +--- +GlobalValueMap: + 42: + - TypeTests: [123] +TypeIdMap: + typeid1: + TTRes: + Kind: Unsat + SizeBitWidth: 0 +... Index: llvm/trunk/test/Transforms/LowerTypeTests/export-nothing.ll =================================================================== --- llvm/trunk/test/Transforms/LowerTypeTests/export-nothing.ll +++ llvm/trunk/test/Transforms/LowerTypeTests/export-nothing.ll @@ -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: ... Index: llvm/trunk/test/Transforms/LowerTypeTests/import-unsat.ll =================================================================== --- llvm/trunk/test/Transforms/LowerTypeTests/import-unsat.ll +++ llvm/trunk/test/Transforms/LowerTypeTests/import-unsat.ll @@ -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 +}