Constant *Mask;
};
-struct LowerTypeTests : public ModulePass {
- static char ID;
- LowerTypeTests() : ModulePass(ID) {
- initializeLowerTypeTestsPass(*PassRegistry::getPassRegistry());
- }
-
- Module *M;
+class LowerTypeTestsModule {
+ Module &M;
bool LinkerSubsectionsViaSymbols;
Triple::ArchType Arch;
Triple::ObjectFormatType ObjectFormat;
- IntegerType *Int1Ty;
- IntegerType *Int8Ty;
- IntegerType *Int32Ty;
- Type *Int32PtrTy;
- IntegerType *Int64Ty;
- IntegerType *IntPtrTy;
+
+ IntegerType *Int1Ty = Type::getInt1Ty(M.getContext());
+ IntegerType *Int8Ty = Type::getInt8Ty(M.getContext());
+ IntegerType *Int32Ty = Type::getInt32Ty(M.getContext());
+ PointerType *Int32PtrTy = PointerType::getUnqual(Int32Ty);
+ IntegerType *Int64Ty = Type::getInt64Ty(M.getContext());
+ IntegerType *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext(), 0);
// Indirect function call index assignment counter for WebAssembly
- uint64_t IndirectIndex;
+ uint64_t IndirectIndex = 1;
// Mapping from type identifiers to the call sites that test them.
DenseMap<Metadata *, std::vector<CallInst *>> TypeTestCallSites;
ArrayRef<Function *> Functions);
void buildBitSetsFromDisjointSet(ArrayRef<Metadata *> TypeIds,
ArrayRef<GlobalObject *> Globals);
+
+public:
+ LowerTypeTestsModule(Module &M);
bool lower();
- bool runOnModule(Module &M) override;
+};
+
+struct LowerTypeTests : public ModulePass {
+ static char ID;
+ LowerTypeTests() : ModulePass(ID) {
+ initializeLowerTypeTestsPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnModule(Module &M) override {
+ if (skipModule(M))
+ return false;
+ return LowerTypeTestsModule(M).lower();
+ }
};
} // anonymous namespace
/// Build a bit set for TypeId using the object layouts in
/// GlobalLayout.
-BitSetInfo LowerTypeTests::buildBitSet(
+BitSetInfo LowerTypeTestsModule::buildBitSet(
Metadata *TypeId, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) {
BitSetBuilder BSB;
return B.CreateICmpNE(MaskedBits, ConstantInt::get(BitsType, 0));
}
-ByteArrayInfo *LowerTypeTests::createByteArray(BitSetInfo &BSI) {
+ByteArrayInfo *LowerTypeTestsModule::createByteArray(BitSetInfo &BSI) {
// Create globals to stand in for byte arrays and masks. These never actually
// get initialized, we RAUW and erase them later in allocateByteArrays() once
// we know the offset and mask to use.
auto ByteArrayGlobal = new GlobalVariable(
- *M, Int8Ty, /*isConstant=*/true, GlobalValue::PrivateLinkage, nullptr);
- auto MaskGlobal = new GlobalVariable(*M, Int8Ty, /*isConstant=*/true,
+ M, Int8Ty, /*isConstant=*/true, GlobalValue::PrivateLinkage, nullptr);
+ auto MaskGlobal = new GlobalVariable(M, Int8Ty, /*isConstant=*/true,
GlobalValue::PrivateLinkage, nullptr);
ByteArrayInfos.emplace_back();
return BAI;
}
-void LowerTypeTests::allocateByteArrays() {
+void LowerTypeTestsModule::allocateByteArrays() {
std::stable_sort(ByteArrayInfos.begin(), ByteArrayInfos.end(),
[](const ByteArrayInfo &BAI1, const ByteArrayInfo &BAI2) {
return BAI1.BitSize > BAI2.BitSize;
cast<GlobalVariable>(BAI->Mask->getOperand(0))->eraseFromParent();
}
- Constant *ByteArrayConst = ConstantDataArray::get(M->getContext(), BAB.Bytes);
+ Constant *ByteArrayConst = ConstantDataArray::get(M.getContext(), BAB.Bytes);
auto ByteArray =
- new GlobalVariable(*M, ByteArrayConst->getType(), /*isConstant=*/true,
+ new GlobalVariable(M, ByteArrayConst->getType(), /*isConstant=*/true,
GlobalValue::PrivateLinkage, ByteArrayConst);
for (unsigned I = 0; I != ByteArrayInfos.size(); ++I) {
BAI->ByteArray->replaceAllUsesWith(GEP);
} else {
GlobalAlias *Alias = GlobalAlias::create(
- Int8Ty, 0, GlobalValue::PrivateLinkage, "bits", GEP, M);
+ Int8Ty, 0, GlobalValue::PrivateLinkage, "bits", GEP, &M);
BAI->ByteArray->replaceAllUsesWith(Alias);
}
BAI->ByteArray->eraseFromParent();
/// Build a test that bit BitOffset is set in BSI, where
/// BitSetGlobal is a global containing the bits in BSI.
-Value *LowerTypeTests::createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI,
- ByteArrayInfo *&BAI, Value *BitOffset) {
+Value *LowerTypeTestsModule::createBitSetTest(IRBuilder<> &B, BitSetInfo &BSI,
+ ByteArrayInfo *&BAI,
+ Value *BitOffset) {
if (BSI.BitSize <= 64) {
// If the bit set is sufficiently small, we can avoid a load by bit testing
// a constant.
// improving the security of the CFI mechanism based on this pass.
ByteArray = GlobalAlias::create(BAI->ByteArray->getValueType(), 0,
GlobalValue::PrivateLinkage, "bits_use",
- ByteArray, M);
+ ByteArray, &M);
}
Value *ByteAddr = B.CreateGEP(Ty, ByteArray, BitOffset);
/// Lower a llvm.type.test call to its implementation. Returns the value to
/// replace the call with.
-Value *LowerTypeTests::lowerBitSetCall(
+Value *LowerTypeTestsModule::lowerBitSetCall(
CallInst *CI, BitSetInfo &BSI, ByteArrayInfo *&BAI,
Constant *CombinedGlobalIntAddr,
const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) {
Value *Ptr = CI->getArgOperand(0);
- const DataLayout &DL = M->getDataLayout();
+ const DataLayout &DL = M.getDataLayout();
if (BSI.containsValue(DL, GlobalLayout, Ptr))
- return ConstantInt::getTrue(M->getContext());
+ return ConstantInt::getTrue(M.getContext());
Constant *OffsetedGlobalAsInt = ConstantExpr::getAdd(
CombinedGlobalIntAddr, ConstantInt::get(IntPtrTy, BSI.ByteOffset));
/// Given a disjoint set of type identifiers and globals, lay out the globals,
/// build the bit sets and lower the llvm.type.test calls.
-void LowerTypeTests::buildBitSetsFromGlobalVariables(
+void LowerTypeTestsModule::buildBitSetsFromGlobalVariables(
ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalVariable *> Globals) {
// Build a new global with the combined contents of the referenced globals.
// This global is a struct whose even-indexed elements contain the original
// contents of the referenced globals and whose odd-indexed elements contain
// any padding required to align the next element to the next power of 2.
std::vector<Constant *> GlobalInits;
- const DataLayout &DL = M->getDataLayout();
+ const DataLayout &DL = M.getDataLayout();
for (GlobalVariable *G : Globals) {
GlobalInits.push_back(G->getInitializer());
uint64_t InitSize = DL.getTypeAllocSize(G->getValueType());
}
if (!GlobalInits.empty())
GlobalInits.pop_back();
- Constant *NewInit = ConstantStruct::getAnon(M->getContext(), GlobalInits);
+ Constant *NewInit = ConstantStruct::getAnon(M.getContext(), GlobalInits);
auto *CombinedGlobal =
- new GlobalVariable(*M, NewInit->getType(), /*isConstant=*/true,
+ new GlobalVariable(M, NewInit->getType(), /*isConstant=*/true,
GlobalValue::PrivateLinkage, NewInit);
StructType *NewTy = cast<StructType>(NewInit->getType());
assert(Globals[I]->getType()->getAddressSpace() == 0);
GlobalAlias *GAlias = GlobalAlias::create(NewTy->getElementType(I * 2), 0,
Globals[I]->getLinkage(), "",
- CombinedGlobalElemPtr, M);
+ CombinedGlobalElemPtr, &M);
GAlias->setVisibility(Globals[I]->getVisibility());
GAlias->takeName(Globals[I]);
Globals[I]->replaceAllUsesWith(GAlias);
}
}
-void LowerTypeTests::lowerTypeTestCalls(
+void LowerTypeTestsModule::lowerTypeTestCalls(
ArrayRef<Metadata *> TypeIds, Constant *CombinedGlobalAddr,
const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) {
Constant *CombinedGlobalIntAddr =
}
}
-void LowerTypeTests::verifyTypeMDNode(GlobalObject *GO, MDNode *Type) {
+void LowerTypeTestsModule::verifyTypeMDNode(GlobalObject *GO, MDNode *Type) {
if (Type->getNumOperands() != 2)
report_fatal_error("All operands of type metadata must have 2 elements");
static const unsigned kX86JumpTableEntrySize = 8;
-unsigned LowerTypeTests::getJumpTableEntrySize() {
+unsigned LowerTypeTestsModule::getJumpTableEntrySize() {
return kX86JumpTableEntrySize;
}
// consists of an instruction sequence containing a relative branch to Dest. The
// constant will be laid out at address Src+(Len*Distance) where Len is the
// target-specific jump table entry size.
-Constant *LowerTypeTests::createJumpTableEntry(GlobalObject *Src,
- Function *Dest,
- unsigned Distance) {
+Constant *LowerTypeTestsModule::createJumpTableEntry(GlobalObject *Src,
+ Function *Dest,
+ unsigned Distance) {
const unsigned kJmpPCRel32Code = 0xe9;
const unsigned kInt3Code = 0xcc;
return ConstantStruct::getAnon(Fields, /*Packed=*/true);
}
-Type *LowerTypeTests::getJumpTableEntryType() {
- return StructType::get(M->getContext(),
+Type *LowerTypeTestsModule::getJumpTableEntryType() {
+ return StructType::get(M.getContext(),
{Int8Ty, Int32Ty, Int8Ty, Int8Ty, Int8Ty},
/*Packed=*/true);
}
/// Given a disjoint set of type identifiers and functions, build the bit sets
/// and lower the llvm.type.test calls, architecture dependently.
-void LowerTypeTests::buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
- ArrayRef<Function *> Functions) {
+void LowerTypeTestsModule::buildBitSetsFromFunctions(
+ ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
if (Arch == Triple::x86 || Arch == Triple::x86_64)
buildBitSetsFromFunctionsX86(TypeIds, Functions);
else if (Arch == Triple::wasm32 || Arch == Triple::wasm64)
/// Given a disjoint set of type identifiers and functions, build a jump table
/// for the functions, build the bit sets and lower the llvm.type.test calls.
-void LowerTypeTests::buildBitSetsFromFunctionsX86(
+void LowerTypeTestsModule::buildBitSetsFromFunctionsX86(
ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
// Unlike the global bitset builder, the function bitset builder cannot
// re-arrange functions in a particular order and base its calculations on the
// Create a constant to hold the jump table.
ArrayType *JumpTableType =
ArrayType::get(getJumpTableEntryType(), Functions.size());
- auto JumpTable = new GlobalVariable(*M, JumpTableType,
+ auto JumpTable = new GlobalVariable(M, JumpTableType,
/*isConstant=*/true,
GlobalValue::PrivateLinkage, nullptr);
JumpTable->setSection(ObjectFormat == Triple::MachO
assert(Functions[I]->getType()->getAddressSpace() == 0);
GlobalAlias *GAlias = GlobalAlias::create(Functions[I]->getValueType(), 0,
Functions[I]->getLinkage(), "",
- CombinedGlobalElemPtr, M);
+ CombinedGlobalElemPtr, &M);
GAlias->setVisibility(Functions[I]->getVisibility());
GAlias->takeName(Functions[I]);
Functions[I]->replaceAllUsesWith(GAlias);
/// table in the backend, it will assign the given indexes.
/// Note: Dynamic linking is not supported, as the WebAssembly ABI has not yet
/// been finalized.
-void LowerTypeTests::buildBitSetsFromFunctionsWASM(
+void LowerTypeTestsModule::buildBitSetsFromFunctionsWASM(
ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
assert(!Functions.empty());
// The indirect function table index space starts at zero, so pass a NULL
// pointer as the subtracted "jump table" offset.
- lowerTypeTestCalls(TypeIds,
- ConstantPointerNull::get(cast<PointerType>(Int32PtrTy)),
+ lowerTypeTestCalls(TypeIds, ConstantPointerNull::get(Int32PtrTy),
GlobalLayout);
}
-void LowerTypeTests::buildBitSetsFromDisjointSet(
+void LowerTypeTestsModule::buildBitSetsFromDisjointSet(
ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalObject *> Globals) {
llvm::DenseMap<Metadata *, uint64_t> TypeIdIndices;
for (unsigned I = 0; I != TypeIds.size(); ++I)
}
/// Lower all type tests in this module.
-bool LowerTypeTests::lower() {
+LowerTypeTestsModule::LowerTypeTestsModule(Module &M) : M(M) {
+ Triple TargetTriple(M.getTargetTriple());
+ LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX();
+ Arch = TargetTriple.getArch();
+ ObjectFormat = TargetTriple.getObjectFormat();
+}
+
+bool LowerTypeTestsModule::lower() {
Function *TypeTestFunc =
- M->getFunction(Intrinsic::getName(Intrinsic::type_test));
+ M.getFunction(Intrinsic::getName(Intrinsic::type_test));
if (!TypeTestFunc || TypeTestFunc->use_empty())
return false;
llvm::DenseMap<Metadata *, unsigned> TypeIdIndices;
unsigned I = 0;
SmallVector<MDNode *, 2> Types;
- for (GlobalObject &GO : M->global_objects()) {
+ for (GlobalObject &GO : M.global_objects()) {
Types.clear();
GO.getMetadata(LLVMContext::MD_type, Types);
for (MDNode *Type : Types) {
GlobalClassesTy::member_iterator CurSet = GlobalClasses.findLeader(GCI);
// Add the referenced globals to the type identifier's equivalence class.
- for (GlobalObject &GO : M->global_objects()) {
+ for (GlobalObject &GO : M.global_objects()) {
Types.clear();
GO.getMetadata(LLVMContext::MD_type, Types);
for (MDNode *Type : Types)
return true;
}
-// Initialization helper shared by the old and the new PM.
-static void init(LowerTypeTests *LTT, Module &M) {
- LTT->M = &M;
- const DataLayout &DL = M.getDataLayout();
- Triple TargetTriple(M.getTargetTriple());
- LTT->LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX();
- LTT->Arch = TargetTriple.getArch();
- LTT->ObjectFormat = TargetTriple.getObjectFormat();
- LTT->Int1Ty = Type::getInt1Ty(M.getContext());
- LTT->Int8Ty = Type::getInt8Ty(M.getContext());
- LTT->Int32Ty = Type::getInt32Ty(M.getContext());
- LTT->Int32PtrTy = PointerType::getUnqual(LTT->Int32Ty);
- LTT->Int64Ty = Type::getInt64Ty(M.getContext());
- LTT->IntPtrTy = DL.getIntPtrType(M.getContext(), 0);
- LTT->TypeTestCallSites.clear();
- LTT->IndirectIndex = 1;
-}
-
-bool LowerTypeTests::runOnModule(Module &M) {
- if (skipModule(M))
- return false;
- init(this, M);
- return lower();
-}
-
PreservedAnalyses LowerTypeTestsPass::run(Module &M,
ModuleAnalysisManager &AM) {
LowerTypeTests Impl;
- init(&Impl, M);
- bool Changed = Impl.lower();
+ bool Changed = LowerTypeTestsModule(M).lower();
if (!Changed)
return PreservedAnalyses::all();
return PreservedAnalyses::none();