Skip to content

Commit

Permalink
Introduce bitset metadata format and bitset lowering pass.
Browse files Browse the repository at this point in the history
This patch introduces a new mechanism that allows IR modules to co-operatively
build pointer sets corresponding to addresses within a given set of
globals. One particular use case for this is to allow a C++ program to
efficiently verify (at each call site) that a vtable pointer is in the set
of valid vtable pointers for the class or its derived classes. One way of
doing this is for a toolchain component to build, for each class, a bit set
that maps to the memory region allocated for the vtables, such that each 1
bit in the bit set maps to a valid vtable for that class, and lay out the
vtables next to each other, to minimize the total size of the bit sets.

The patch introduces a metadata format for representing pointer sets, an
'@llvm.bitset.test' intrinsic and an LTO lowering pass that lays out the globals
and builds the bitsets, and documents the new feature.

Differential Revision: http://reviews.llvm.org/D7288

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@230054 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
pcc committed Feb 20, 2015
1 parent b2e79a8 commit 5a81e14
Show file tree
Hide file tree
Showing 21 changed files with 1,014 additions and 2 deletions.
66 changes: 66 additions & 0 deletions docs/BitSets.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
=======
Bitsets
=======

This is a mechanism that allows IR modules to co-operatively build pointer
sets corresponding to addresses within a given set of globals. One example
of a use case for this is to allow a C++ program to efficiently verify (at
each call site) that a vtable pointer is in the set of valid vtable pointers
for the type of the class or its derived classes.

To use the mechanism, a client creates a global metadata node named
``llvm.bitsets``. Each element is a metadata node with three elements:
the first is a metadata string containing an identifier for the bitset,
the second is a global variable and the third is a byte offset into the
global variable.

This will cause a link-time optimization pass to generate bitsets from the
memory addresses referenced from the elements of the bitset metadata. The pass
will lay out the referenced globals consecutively, so their definitions must
be available at LTO time. An intrinsic, :ref:`llvm.bitset.test <bitset.test>`,
generates code to test whether a given pointer is a member of a bitset.

:Example:

::

target datalayout = "e-p:32:32"

@a = internal global i32 0
@b = internal global i32 0
@c = internal global i32 0
@d = internal global [2 x i32] [i32 0, i32 0]

!llvm.bitsets = !{!0, !1, !2, !3, !4}

!0 = !{!"bitset1", i32* @a, i32 0}
!1 = !{!"bitset1", i32* @b, i32 0}
!2 = !{!"bitset2", i32* @b, i32 0}
!3 = !{!"bitset2", i32* @c, i32 0}
!4 = !{!"bitset2", i32* @d, i32 4}

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone

define i1 @foo(i32* %p) {
%pi8 = bitcast i32* %p to i8*
%x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset1")
ret i1 %x
}

define i1 @bar(i32* %p) {
%pi8 = bitcast i32* %p to i8*
%x = call i1 @llvm.bitset.test(i8* %pi8, metadata !"bitset2")
ret i1 %x
}

define void @main() {
%a1 = call i1 @foo(i32* @a) ; returns 1
%b1 = call i1 @foo(i32* @b) ; returns 1
%c1 = call i1 @foo(i32* @c) ; returns 0
%a2 = call i1 @bar(i32* @a) ; returns 0
%b2 = call i1 @bar(i32* @b) ; returns 1
%c2 = call i1 @bar(i32* @c) ; returns 1
%d02 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 0)) ; returns 0
%d12 = call i1 @bar(i32* getelementptr ([2 x i32]* @d, i32 0, i32 1)) ; returns 1
ret void
}
31 changes: 31 additions & 0 deletions docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3308,6 +3308,12 @@ the loop identifier metadata node directly:
!1 = !{!1} ; an identifier for the inner loop
!2 = !{!2} ; an identifier for the outer loop
'``llvm.bitsets``'
^^^^^^^^^^^^^^^^^^

The ``llvm.bitsets`` global metadata is used to implement
:doc:`bitsets <BitSets>`.

Module Flags Metadata
=====================

Expand Down Expand Up @@ -9891,6 +9897,31 @@ sufficient overall improvement in code quality. For this reason,
that the optimizer can otherwise deduce or facts that are of little use to the
optimizer.

.. _bitset.test:

'``llvm.bitset.test``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

::

declare i1 @llvm.bitset.test(i8* %ptr, metadata %bitset) nounwind readnone


Arguments:
""""""""""

The first argument is a pointer to be tested. The second argument is a
metadata string containing the name of a :doc:`bitset <BitSets>`.

Overview:
"""""""""

The ``llvm.bitset.test`` intrinsic tests whether the given pointer is a
member of the given bitset.

'``llvm.donothing``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ For API clients and LLVM developers.
CoverageMappingFormat
Statepoints
MergeFunctions
BitSets

:doc:`WritingAnLLVMPass`
Information on how to write LLVM transformations and analyses.
Expand Down
2 changes: 1 addition & 1 deletion include/llvm/ADT/EquivalenceClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class EquivalenceClasses {
assert(Node != nullptr && "Dereferencing end()!");
return Node->getData();
}
reference operator->() const { return operator*(); }
pointer operator->() const { return &operator*(); }

member_iterator &operator++() {
assert(Node != nullptr && "++'d off the end of the list!");
Expand Down
6 changes: 6 additions & 0 deletions include/llvm/ADT/PointerUnion.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ namespace llvm {
return lhs.getOpaqueValue() != rhs.getOpaqueValue();
}

template<typename PT1, typename PT2>
static bool operator<(PointerUnion<PT1, PT2> lhs,
PointerUnion<PT1, PT2> rhs) {
return lhs.getOpaqueValue() < rhs.getOpaqueValue();
}

// Teach SmallPtrSet that PointerUnion is "basically a pointer", that has
// # low bits available = min(PT1bits,PT2bits)-1.
template<typename PT1, typename PT2>
Expand Down
4 changes: 4 additions & 0 deletions include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,10 @@ def int_masked_scatter: Intrinsic<[],
LLVMVectorSameWidth<0, llvm_i1_ty>],
[IntrReadWriteArgMem]>;

// Intrinsics to support bit sets.
def int_bitset_test : Intrinsic<[llvm_i1_ty], [llvm_ptr_ty, llvm_metadata_ty],
[IntrNoMem]>;

//===----------------------------------------------------------------------===//
// Target-specific intrinsics
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ void initializeLoopUnrollPass(PassRegistry&);
void initializeLoopUnswitchPass(PassRegistry&);
void initializeLoopIdiomRecognizePass(PassRegistry&);
void initializeLowerAtomicPass(PassRegistry&);
void initializeLowerBitSetsPass(PassRegistry&);
void initializeLowerExpectIntrinsicPass(PassRegistry&);
void initializeLowerIntrinsicsPass(PassRegistry&);
void initializeLowerInvokePass(PassRegistry&);
Expand Down
4 changes: 4 additions & 0 deletions include/llvm/Transforms/IPO.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ ModulePass *createMetaRenamerPass();
/// manager.
ModulePass *createBarrierNoopPass();

/// \brief This pass lowers bitset metadata and the llvm.bitset.test intrinsic
/// to bitsets.
ModulePass *createLowerBitSetsPass();

} // End llvm namespace

#endif
78 changes: 78 additions & 0 deletions include/llvm/Transforms/IPO/LowerBitSets.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//===- LowerBitSets.h - Bitset lowering pass --------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines parts of the bitset lowering pass implementation that may
// be usefully unit tested.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_TRANSFORMS_IPO_LOWERBITSETS_H
#define LLVM_TRANSFORMS_IPO_LOWERBITSETS_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"

#include <stdint.h>
#include <limits>
#include <vector>

namespace llvm {

class DataLayout;
class GlobalVariable;
class Value;

struct BitSetInfo {
// The actual bitset.
std::vector<uint8_t> Bits;

// The byte offset into the combined global represented by the bitset.
uint64_t ByteOffset;

// The size of the bitset in bits.
uint64_t BitSize;

// Log2 alignment of the bit set relative to the combined global.
// For example, a log2 alignment of 3 means that bits in the bitset
// represent addresses 8 bytes apart.
unsigned AlignLog2;

bool isSingleOffset() const {
return Bits.size() == 1 && Bits[0] == 1;
}

bool containsGlobalOffset(uint64_t Offset) const;

bool containsValue(const DataLayout *DL,
const DenseMap<GlobalVariable *, uint64_t> &GlobalLayout,
Value *V, uint64_t COffset = 0) const;

};

struct BitSetBuilder {
SmallVector<uint64_t, 16> Offsets;
uint64_t Min, Max;

BitSetBuilder() : Min(std::numeric_limits<uint64_t>::max()), Max(0) {}

void addOffset(uint64_t Offset) {
if (Min > Offset)
Min = Offset;
if (Max < Offset)
Max = Offset;

Offsets.push_back(Offset);
}

BitSetInfo build();
};

} // namespace llvm

#endif
1 change: 1 addition & 0 deletions lib/Transforms/IPO/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_llvm_library(LLVMipo
Inliner.cpp
Internalize.cpp
LoopExtractor.cpp
LowerBitSets.cpp
MergeFunctions.cpp
PartialInlining.cpp
PassManagerBuilder.cpp
Expand Down
1 change: 1 addition & 0 deletions lib/Transforms/IPO/IPO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ void llvm::initializeIPO(PassRegistry &Registry) {
initializeLoopExtractorPass(Registry);
initializeBlockExtractorPassPass(Registry);
initializeSingleLoopExtractorPass(Registry);
initializeLowerBitSetsPass(Registry);
initializeMergeFunctionsPass(Registry);
initializePartialInlinerPass(Registry);
initializePruneEHPass(Registry);
Expand Down
Loading

0 comments on commit 5a81e14

Please sign in to comment.