Index: llvm/trunk/include/llvm/InitializePasses.h =================================================================== --- llvm/trunk/include/llvm/InitializePasses.h +++ llvm/trunk/include/llvm/InitializePasses.h @@ -85,6 +85,7 @@ void initializeBranchRelaxationPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); void initializeBreakFalseDepsPass(PassRegistry&); +void initializeCanonicalizeAliasesLegacyPassPass(PassRegistry &); void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&); void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&); void initializeCFGPrinterLegacyPassPass(PassRegistry&); Index: llvm/trunk/include/llvm/Transforms/Scalar.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Scalar.h +++ llvm/trunk/include/llvm/Transforms/Scalar.h @@ -471,6 +471,7 @@ ///===---------------------------------------------------------------------===// ModulePass *createNameAnonGlobalPass(); +ModulePass *createCanonicalizeAliasesPass(); //===----------------------------------------------------------------------===// // Index: llvm/trunk/include/llvm/Transforms/Utils/CanonicalizeAliases.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Utils/CanonicalizeAliases.h +++ llvm/trunk/include/llvm/Transforms/Utils/CanonicalizeAliases.h @@ -0,0 +1,32 @@ +//===-- 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 { + +/// Simple pass that canonicalizes aliases. +class CanonicalizeAliasesPass : public PassInfoMixin { +public: + CanonicalizeAliasesPass() = default; + + PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_UTILS_CANONICALIZE_ALIASESH Index: llvm/trunk/lib/Passes/PassBuilder.cpp =================================================================== --- llvm/trunk/lib/Passes/PassBuilder.cpp +++ llvm/trunk/lib/Passes/PassBuilder.cpp @@ -153,6 +153,7 @@ #include "llvm/Transforms/Scalar/WarnMissedTransforms.h" #include "llvm/Transforms/Utils/AddDiscriminators.h" #include "llvm/Transforms/Utils/BreakCriticalEdges.h" +#include "llvm/Transforms/Utils/CanonicalizeAliases.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/LCSSA.h" #include "llvm/Transforms/Utils/LibCallsShrinkWrap.h" Index: llvm/trunk/lib/Passes/PassRegistry.def =================================================================== --- llvm/trunk/lib/Passes/PassRegistry.def +++ llvm/trunk/lib/Passes/PassRegistry.def @@ -42,6 +42,7 @@ #endif MODULE_PASS("always-inline", AlwaysInlinerPass()) MODULE_PASS("called-value-propagation", CalledValuePropagationPass()) +MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass()) MODULE_PASS("cg-profile", CGProfilePass()) MODULE_PASS("constmerge", ConstantMergePass()) MODULE_PASS("cross-dso-cfi", CrossDSOCFIPass()) Index: llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp +++ llvm/trunk/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -462,12 +462,14 @@ addExtensionsToPM(EP_EnabledOnOptLevel0, MPM); - // Rename anon globals to be able to export them in the summary. - // This has to be done after we add the extensions to the pass manager - // as there could be passes (e.g. Adddress sanitizer) which introduce - // new unnamed globals. - if (PrepareForLTO || PrepareForThinLTO) + if (PrepareForLTO || PrepareForThinLTO) { + MPM.add(createCanonicalizeAliasesPass()); + // Rename anon globals to be able to export them in the summary. + // This has to be done after we add the extensions to the pass manager + // as there could be passes (e.g. Adddress sanitizer) which introduce + // new unnamed globals. MPM.add(createNameAnonGlobalPass()); + } return; } @@ -585,6 +587,7 @@ // Ensure we perform any last passes, but do so before renaming anonymous // globals in case the passes add any. addExtensionsToPM(EP_OptimizerLast, MPM); + MPM.add(createCanonicalizeAliasesPass()); // Rename anon globals to be able to export them in the summary. MPM.add(createNameAnonGlobalPass()); return; @@ -744,9 +747,11 @@ addExtensionsToPM(EP_OptimizerLast, MPM); - // Rename anon globals to be able to handle them in the summary - if (PrepareForLTO) + if (PrepareForLTO) { + MPM.add(createCanonicalizeAliasesPass()); + // Rename anon globals to be able to handle them in the summary MPM.add(createNameAnonGlobalPass()); + } } void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { Index: llvm/trunk/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/trunk/lib/Transforms/Utils/CMakeLists.txt +++ llvm/trunk/lib/Transforms/Utils/CMakeLists.txt @@ -6,6 +6,7 @@ BuildLibCalls.cpp BypassSlowDivision.cpp CallPromotionUtils.cpp + CanonicalizeAliases.cpp CloneFunction.cpp CloneModule.cpp CodeExtractor.cpp Index: llvm/trunk/lib/Transforms/Utils/CanonicalizeAliases.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/CanonicalizeAliases.cpp +++ llvm/trunk/lib/Transforms/Utils/CanonicalizeAliases.cpp @@ -0,0 +1,105 @@ +//===- 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. +// +//===----------------------------------------------------------------------===// +// +// Currently this file implements partial alias canonicalization, to +// flatten chains of aliases (also done by GlobalOpt, but not on for +// O0 compiles). E.g. +// @a = alias i8, i8 *@b +// @b = alias i8, i8 *@g +// +// will be converted to: +// @a = alias i8, i8 *@g <-- @a is now an alias to base object @g +// @b = alias i8, i8 *@g +// +// Eventually this file will implement full alias canonicalation, 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; + +namespace { + +static Constant *canonicalizeAlias(Constant *C, bool &Changed) { + if (auto *GA = dyn_cast(C)) { + auto *NewAliasee = canonicalizeAlias(GA->getAliasee(), Changed); + if (NewAliasee != GA->getAliasee()) { + GA->setAliasee(NewAliasee); + Changed = true; + } + return NewAliasee; + } + + auto *CE = dyn_cast(C); + if (!CE) + return C; + + std::vector Ops; + for (Use &U : CE->operands()) + Ops.push_back(canonicalizeAlias(cast(U), Changed)); + return CE->getWithOperands(Ops); +} + +/// Convert aliases to canonical form. +static bool canonicalizeAliases(Module &M) { + bool Changed = false; + for (auto &GA : M.aliases()) + canonicalizeAlias(&GA, Changed); + return Changed; +} + +// 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 CanonicalizeAliasesPass::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(); +} +} // namespace llvm Index: llvm/trunk/lib/Transforms/Utils/Utils.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/Utils.cpp +++ llvm/trunk/lib/Transforms/Utils/Utils.cpp @@ -26,6 +26,7 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) { initializeAddDiscriminatorsLegacyPassPass(Registry); initializeBreakCriticalEdgesPass(Registry); + initializeCanonicalizeAliasesLegacyPassPass(Registry); initializeInstNamerPass(Registry); initializeLCSSAWrapperPassPass(Registry); initializeLibCallsShrinkWrapLegacyPassPass(Registry); Index: llvm/trunk/test/Transforms/CanonicalizeAliases/canonicalize.ll =================================================================== --- llvm/trunk/test/Transforms/CanonicalizeAliases/canonicalize.ll +++ llvm/trunk/test/Transforms/CanonicalizeAliases/canonicalize.ll @@ -0,0 +1,37 @@ +; RUN: opt -S -canonicalize-aliases < %s | FileCheck %s +; RUN: opt -prepare-for-thinlto -O0 -module-summary -o - < %s | llvm-dis -o - | FileCheck %s +; RUN: opt -S -passes=canonicalize-aliases < %s | FileCheck %s + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; CHECK-DAG: @analias = alias void (), void ()* @aliasee +; CHECK-DAG: @anotheralias = alias void (), void ()* @aliasee +; CHECK-DAG: define void @aliasee() + +@analias = alias void (), void ()* @anotheralias +@anotheralias = alias void (), bitcast (void ()* @aliasee to void ()*) + +; Function Attrs: nounwind uwtable +define void @aliasee() #0 { +entry: + ret void +} + +%struct.S1 = type { i32, i32, i32 } + +; CHECK-DAG: @S = global %struct.S1 { i32 31, i32 32, i32 33 } +; CHECK-DAG: @Salias = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @S, i32 0, i32 1) +; CHECK-DAG: @Salias2 = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @S, i32 0, i32 1) +; CHECK-DAG: @Salias3 = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @S, i32 0, i32 1) + +@S = global %struct.S1 { i32 31, i32 32, i32 33 }, align 4 +@Salias = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @S, i32 0, i32 1) +@Salias2 = alias i32, i32* @Salias +@Salias3 = alias i32, i32* @Salias2 + +; CHECK-DAG: @Salias4 = alias %struct.S1, %struct.S1* @S +; CHECK-DAG: @Salias5 = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @S, i32 0, i32 1) + +@Salias4 = alias %struct.S1, %struct.S1* @S +@Salias5 = alias i32, getelementptr inbounds (%struct.S1, %struct.S1* @Salias4, i32 0, i32 1)