Index: include/llvm/InitializePasses.h =================================================================== --- include/llvm/InitializePasses.h +++ include/llvm/InitializePasses.h @@ -81,6 +81,7 @@ void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry&); void initializeBranchRelaxationPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); +void initializeCanonicalizeAliasesLegacyPassPass(PassRegistry &); void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&); void initializeCFGPrinterLegacyPassPass(PassRegistry&); void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&); Index: include/llvm/Transforms/Scalar.h =================================================================== --- include/llvm/Transforms/Scalar.h +++ include/llvm/Transforms/Scalar.h @@ -551,6 +551,7 @@ ///===---------------------------------------------------------------------===// ModulePass *createNameAnonGlobalPass(); +ModulePass *createCanonicalizeAliasesPass(); //===----------------------------------------------------------------------===// // Index: include/llvm/Transforms/Utils/CanonicalizeAliases.h =================================================================== --- /dev/null +++ include/llvm/Transforms/Utils/CanonicalizeAliases.h @@ -0,0 +1,34 @@ +//===-- CanonicalizeAliases.h - Alias Canonicalization 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 canonicalizes aliases. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_CANONICALIZE_ALIASES_H +#define LLVM_TRANSFORMS_UTILS_CANONICALIZE_ALIASES_H + +#include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" + +namespace llvm { + +bool canonicalizeAliases(Module &M); + +/// Simple pass that canonicalizes aliases. +class CanonicalizeAliases : public PassInfoMixin { +public: + CanonicalizeAliases() = default; + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_CANONICALIZE_ALIASESH Index: lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- lib/Transforms/IPO/PassManagerBuilder.cpp +++ lib/Transforms/IPO/PassManagerBuilder.cpp @@ -409,9 +409,11 @@ else if (!GlobalExtensions->empty() || !Extensions.empty()) MPM.add(createBarrierNoopPass()); - if (PrepareForThinLTO) + if (PrepareForThinLTO) { + MPM.add(createCanonicalizeAliasesPass()); // Rename anon globals to be able to export them in the summary. MPM.add(createNameAnonGlobalPass()); + } addExtensionsToPM(EP_EnabledOnOptLevel0, MPM); return; @@ -507,6 +509,7 @@ // unrolling/vectorization/... now. We'll first run the inliner + CGSCC passes // during ThinLTO and perform the rest of the optimizations afterward. if (PrepareForThinLTO) { + MPM.add(createCanonicalizeAliasesPass()); // Reduce the size of the IR as much as possible. MPM.add(createGlobalOptimizerPass()); // Rename anon globals to be able to export them in the summary. Index: lib/Transforms/Utils/CMakeLists.txt =================================================================== --- lib/Transforms/Utils/CMakeLists.txt +++ lib/Transforms/Utils/CMakeLists.txt @@ -5,6 +5,7 @@ BreakCriticalEdges.cpp BuildLibCalls.cpp BypassSlowDivision.cpp + CanonicalizeAliases.cpp CloneFunction.cpp CloneModule.cpp CmpInstAnalysis.cpp Index: lib/Transforms/Utils/CanonicalizeAliases.cpp =================================================================== --- /dev/null +++ lib/Transforms/Utils/CanonicalizeAliases.cpp @@ -0,0 +1,144 @@ +//===- CanonicalizeAliases.cpp - ThinLTO Support: Canonicalize Aliases ----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements alias canonicalization, so that all aliasees +// are private anonymous values. E.g. +// @a = alias i8, i8 *@g +// @g = global i8 0 +// +// will be converted to: +// @0 = private global +// @a = alias i8, i8* @0 +// @g = alias i8, i8* @0 +// +// This simplifies optimization and ThinLTO linking of the original symbols. +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/CanonicalizeAliases.h" + +#include "llvm/IR/Operator.h" +#include "llvm/IR/ValueHandle.h" + +using namespace llvm; + +/// Check if the given user is an alias (looking through bit casts). +static bool userIsAlias(Value *V) { + if (isa(V)) + return true; + if (BitCastOperator *BC = dyn_cast(V)) { + for (Use &U : BC->materialized_uses()) { + return userIsAlias(U.getUser()); + } + } + return false; +} + +/// Like replaceAllUsesWith but doesn't replace any uses that are +/// aliases, so that we can just replace uses of the original value +/// with the new private aliasee, but keep the original value name +/// as an alias to it. +static void replaceAllUsesWithExceptAliases(Value *Old, Value *New) { + assert(New && "Value::replaceAllUsesWith() is invalid!"); + assert(New->getType() == Old->getType() && + "replaceAllUses of value with new value of different type!"); + + // Notify all ValueHandles (if present) that this value is going away. + if (Old->hasValueHandle()) + ValueHandleBase::ValueIsRAUWd(Old, New); + if (Old->isUsedByMetadata()) + ValueAsMetadata::handleRAUW(Old, New); + + for (Use &U : Old->materialized_uses()) { + if (userIsAlias(U.getUser())) + continue; + // Must handle Constants specially, we cannot call replaceUsesOfWith on a + // constant because they are uniqued. + if (auto *C = dyn_cast(U.getUser())) { + if (!isa(C)) { + C->handleOperandChange(Old, New); + continue; + } + } + + U.set(New); + } +} + +namespace llvm { +/// Convert aliases to canonical form. +bool canonicalizeAliases(Module &M) { + bool Changed = false; + for (auto &GA : M.aliases()) { + // Check if the aliasee is private already + GlobalObject *GO = GA.getBaseObject(); + if (!GO || GO->hasPrivateLinkage()) + continue; + + // Don't make malformed IR (will be caught by verifier) worse. + if (GO->isDeclarationForLinker()) + continue; + + // Create a new alias to aliasee that keeps the original aliasee name + // and linkage. + auto *NewGA = GlobalAlias::create("", GO); + NewGA->takeName(GO); + + // Make the original aliasee anonymous + GO->setName(""); + + // Change linkage of renamed original aliasee to private + GO->setLinkage(GlobalValue::PrivateLinkage); + + // RAUW all uses of original aliasee with the new alias. + replaceAllUsesWithExceptAliases(GO, NewGA); + + Changed = true; + } + return Changed; +} +} + +namespace { + +// Legacy pass that canonicalizes aliases. +class CanonicalizeAliasesLegacyPass : public ModulePass { + +public: + /// Pass identification, replacement for typeid + static char ID; + + /// Specify pass name for debug output + StringRef getPassName() const override { return "Canonicalize Aliases"; } + + explicit CanonicalizeAliasesLegacyPass() : ModulePass(ID) {} + + bool runOnModule(Module &M) override { return canonicalizeAliases(M); } +}; +char CanonicalizeAliasesLegacyPass::ID = 0; + +} // anonymous namespace + +PreservedAnalyses CanonicalizeAliases::run(Module &M, + ModuleAnalysisManager &AM) { + if (!canonicalizeAliases(M)) + return PreservedAnalyses::all(); + + return PreservedAnalyses::none(); +} + +INITIALIZE_PASS_BEGIN(CanonicalizeAliasesLegacyPass, "canonicalize-aliases", + "Canonicalize aliases", false, false) +INITIALIZE_PASS_END(CanonicalizeAliasesLegacyPass, "canonicalize-aliases", + "Canonicalize aliases", false, false) + +namespace llvm { +ModulePass *createCanonicalizeAliasesPass() { + return new CanonicalizeAliasesLegacyPass(); +} +} Index: lib/Transforms/Utils/Utils.cpp =================================================================== --- lib/Transforms/Utils/Utils.cpp +++ lib/Transforms/Utils/Utils.cpp @@ -23,6 +23,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) { initializeAddDiscriminatorsLegacyPassPass(Registry); initializeBreakCriticalEdgesPass(Registry); + initializeCanonicalizeAliasesLegacyPassPass(Registry); initializeInstNamerPass(Registry); initializeLCSSAWrapperPassPass(Registry); initializeLibCallsShrinkWrapLegacyPassPass(Registry); Index: test/Transforms/CanonicalizeAliases/canonicalize.ll =================================================================== --- /dev/null +++ test/Transforms/CanonicalizeAliases/canonicalize.ll @@ -0,0 +1,22 @@ +; RUN: opt -S -canonicalize-aliases < %s | FileCheck %s +; RUN: opt -prepare-for-thinlto -O0 -module-summary -o - < %s | llvm-dis -o - | FileCheck %s --check-prefix=NAMEDANON + +; CHECK-DAG: @fooalias = alias void (...), bitcast (void ()* @1 +; CHECK-DAG: @foo = alias void (), void ()* @1 +; CHECK-DAG: define private void @1() +; NAMEDANON-DAG: @fooalias = alias void (...), bitcast (void ()* @anon.d41d8cd98f00b204e9800998ecf8427e.0 +; NAMEDANON-DAG: @foo = alias void (), void ()* @anon.d41d8cd98f00b204e9800998ecf8427e.0 +; NAMEDANON-DAG: define private void @anon.d41d8cd98f00b204e9800998ecf8427e.0() +@fooalias = alias void (...), bitcast (void ()* @foo to void (...)*) +define void @foo() { + ret void +} + +; CHECK-DAG: @0 = private global +; CHECK-DAG: @baralias = alias i8, i8* @0 +; CHECK-DAG: @bar = alias i8, i8* @0 +; NAMEDANON-DAG: @anon.d41d8cd98f00b204e9800998ecf8427e.1 = private global +; NAMEDANON-DAG: @baralias = alias i8, i8* @anon.d41d8cd98f00b204e9800998ecf8427e.1 +; NAMEDANON-DAG: @bar = alias i8, i8* @anon.d41d8cd98f00b204e9800998ecf8427e.1 +@baralias = alias i8, i8 *@bar +@bar = global i8 0