003 File Manager
Current Path:
/usr/src/contrib/llvm-project/llvm/lib/Transforms/IPO
usr
/
src
/
contrib
/
llvm-project
/
llvm
/
lib
/
Transforms
/
IPO
/
📁
..
📄
AlwaysInliner.cpp
(6.51 KB)
📄
ArgumentPromotion.cpp
(44.76 KB)
📄
Attributor.cpp
(81.04 KB)
📄
AttributorAttributes.cpp
(269.7 KB)
📄
BarrierNoopPass.cpp
(1.67 KB)
📄
BlockExtractor.cpp
(8.17 KB)
📄
CalledValuePropagation.cpp
(17.71 KB)
📄
ConstantMerge.cpp
(9.59 KB)
📄
CrossDSOCFI.cpp
(5.98 KB)
📄
DeadArgumentElimination.cpp
(42.84 KB)
📄
ElimAvailExtern.cpp
(3.14 KB)
📄
ExtractGV.cpp
(5.2 KB)
📄
ForceFunctionAttrs.cpp
(4.79 KB)
📄
FunctionAttrs.cpp
(55.56 KB)
📄
FunctionImport.cpp
(55.28 KB)
📄
GlobalDCE.cpp
(15.55 KB)
📄
GlobalOpt.cpp
(119.78 KB)
📄
GlobalSplit.cpp
(6.92 KB)
📄
HotColdSplitting.cpp
(26.27 KB)
📄
IPConstantPropagation.cpp
(10.68 KB)
📄
IPO.cpp
(4.94 KB)
📄
InferFunctionAttrs.cpp
(2.89 KB)
📄
InlineSimple.cpp
(4.21 KB)
📄
Inliner.cpp
(44.77 KB)
📄
Internalize.cpp
(9.52 KB)
📄
LoopExtractor.cpp
(7.14 KB)
📄
LowerTypeTests.cpp
(83.98 KB)
📄
MergeFunctions.cpp
(34.12 KB)
📄
OpenMPOpt.cpp
(52.75 KB)
📄
PartialInlining.cpp
(55.67 KB)
📄
PassManagerBuilder.cpp
(49.21 KB)
📄
PruneEH.cpp
(9.54 KB)
📄
SCCP.cpp
(3.22 KB)
📄
SampleProfile.cpp
(77.15 KB)
📄
StripDeadPrototypes.cpp
(2.73 KB)
📄
StripSymbols.cpp
(11.7 KB)
📄
SyntheticCountsPropagation.cpp
(5.64 KB)
📄
ThinLTOBitcodeWriter.cpp
(20.16 KB)
📄
WholeProgramDevirt.cpp
(85.02 KB)
Editing: GlobalSplit.cpp
//===- GlobalSplit.cpp - global variable splitter -------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This pass uses inrange annotations on GEP indices to split globals where // beneficial. Clang currently attaches these annotations to references to // virtual table globals under the Itanium ABI for the benefit of the // whole-program virtual call optimization and control flow integrity passes. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/GlobalSplit.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Transforms/IPO.h" #include <cstdint> #include <vector> using namespace llvm; static bool splitGlobal(GlobalVariable &GV) { // If the address of the global is taken outside of the module, we cannot // apply this transformation. if (!GV.hasLocalLinkage()) return false; // We currently only know how to split ConstantStructs. auto *Init = dyn_cast_or_null<ConstantStruct>(GV.getInitializer()); if (!Init) return false; // Verify that each user of the global is an inrange getelementptr constant. // From this it follows that any loads from or stores to that global must use // a pointer derived from an inrange getelementptr constant, which is // sufficient to allow us to apply the splitting transform. for (User *U : GV.users()) { if (!isa<Constant>(U)) return false; auto *GEP = dyn_cast<GEPOperator>(U); if (!GEP || !GEP->getInRangeIndex() || *GEP->getInRangeIndex() != 1 || !isa<ConstantInt>(GEP->getOperand(1)) || !cast<ConstantInt>(GEP->getOperand(1))->isZero() || !isa<ConstantInt>(GEP->getOperand(2))) return false; } SmallVector<MDNode *, 2> Types; GV.getMetadata(LLVMContext::MD_type, Types); const DataLayout &DL = GV.getParent()->getDataLayout(); const StructLayout *SL = DL.getStructLayout(Init->getType()); IntegerType *Int32Ty = Type::getInt32Ty(GV.getContext()); std::vector<GlobalVariable *> SplitGlobals(Init->getNumOperands()); for (unsigned I = 0; I != Init->getNumOperands(); ++I) { // Build a global representing this split piece. auto *SplitGV = new GlobalVariable(*GV.getParent(), Init->getOperand(I)->getType(), GV.isConstant(), GlobalValue::PrivateLinkage, Init->getOperand(I), GV.getName() + "." + utostr(I)); SplitGlobals[I] = SplitGV; unsigned SplitBegin = SL->getElementOffset(I); unsigned SplitEnd = (I == Init->getNumOperands() - 1) ? SL->getSizeInBytes() : SL->getElementOffset(I + 1); // Rebuild type metadata, adjusting by the split offset. // FIXME: See if we can use DW_OP_piece to preserve debug metadata here. for (MDNode *Type : Types) { uint64_t ByteOffset = cast<ConstantInt>( cast<ConstantAsMetadata>(Type->getOperand(0))->getValue()) ->getZExtValue(); // Type metadata may be attached one byte after the end of the vtable, for // classes without virtual methods in Itanium ABI. AFAIK, it is never // attached to the first byte of a vtable. Subtract one to get the right // slice. // This is making an assumption that vtable groups are the only kinds of // global variables that !type metadata can be attached to, and that they // are either Itanium ABI vtable groups or contain a single vtable (i.e. // Microsoft ABI vtables). uint64_t AttachedTo = (ByteOffset == 0) ? ByteOffset : ByteOffset - 1; if (AttachedTo < SplitBegin || AttachedTo >= SplitEnd) continue; SplitGV->addMetadata( LLVMContext::MD_type, *MDNode::get(GV.getContext(), {ConstantAsMetadata::get( ConstantInt::get(Int32Ty, ByteOffset - SplitBegin)), Type->getOperand(1)})); } if (GV.hasMetadata(LLVMContext::MD_vcall_visibility)) SplitGV->setVCallVisibilityMetadata(GV.getVCallVisibility()); } for (User *U : GV.users()) { auto *GEP = cast<GEPOperator>(U); unsigned I = cast<ConstantInt>(GEP->getOperand(2))->getZExtValue(); if (I >= SplitGlobals.size()) continue; SmallVector<Value *, 4> Ops; Ops.push_back(ConstantInt::get(Int32Ty, 0)); for (unsigned I = 3; I != GEP->getNumOperands(); ++I) Ops.push_back(GEP->getOperand(I)); auto *NewGEP = ConstantExpr::getGetElementPtr( SplitGlobals[I]->getInitializer()->getType(), SplitGlobals[I], Ops, GEP->isInBounds()); GEP->replaceAllUsesWith(NewGEP); } // Finally, remove the original global. Any remaining uses refer to invalid // elements of the global, so replace with undef. if (!GV.use_empty()) GV.replaceAllUsesWith(UndefValue::get(GV.getType())); GV.eraseFromParent(); return true; } static bool splitGlobals(Module &M) { // First, see if the module uses either of the llvm.type.test or // llvm.type.checked.load intrinsics, which indicates that splitting globals // may be beneficial. Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); Function *TypeCheckedLoadFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_checked_load)); if ((!TypeTestFunc || TypeTestFunc->use_empty()) && (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty())) return false; bool Changed = false; for (auto I = M.global_begin(); I != M.global_end();) { GlobalVariable &GV = *I; ++I; Changed |= splitGlobal(GV); } return Changed; } namespace { struct GlobalSplit : public ModulePass { static char ID; GlobalSplit() : ModulePass(ID) { initializeGlobalSplitPass(*PassRegistry::getPassRegistry()); } bool runOnModule(Module &M) override { if (skipModule(M)) return false; return splitGlobals(M); } }; } // end anonymous namespace char GlobalSplit::ID = 0; INITIALIZE_PASS(GlobalSplit, "globalsplit", "Global splitter", false, false) ModulePass *llvm::createGlobalSplitPass() { return new GlobalSplit; } PreservedAnalyses GlobalSplitPass::run(Module &M, ModuleAnalysisManager &AM) { if (!splitGlobals(M)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); }
Upload File
Create Folder