From: Teresa Johnson Date: Fri, 4 Jan 2019 19:04:54 +0000 (+0000) Subject: [ThinLTO] Handle chains of aliases X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=1f63024b270c0eeadc9ca129eebb5c62603f425e;p=llvm [ThinLTO] Handle chains of aliases At -O0, globalopt is not run during the compile step, and we can have a chain of an alias having an immediate aliasee of another alias. The summaries are constructed assuming aliases in a canonical form (flattened chains), and as a result only the base object but no intermediate aliases were preserved. Fix by adding a pass that canonicalize aliases, which ensures each alias is a direct alias of the base object. Reviewers: pcc, davidxl Subscribers: mehdi_amini, inglorion, eraman, steven_wu, dexonsmith, arphaman, llvm-commits Differential Revision: https://reviews.llvm.org/D54507 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@350423 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/InitializePasses.h b/include/llvm/InitializePasses.h index 4aa68888940..293f37ee40c 100644 --- a/include/llvm/InitializePasses.h +++ b/include/llvm/InitializePasses.h @@ -85,6 +85,7 @@ void initializeBranchProbabilityInfoWrapperPassPass(PassRegistry&); void initializeBranchRelaxationPass(PassRegistry&); void initializeBreakCriticalEdgesPass(PassRegistry&); void initializeBreakFalseDepsPass(PassRegistry&); +void initializeCanonicalizeAliasesLegacyPassPass(PassRegistry &); void initializeCFGOnlyPrinterLegacyPassPass(PassRegistry&); void initializeCFGOnlyViewerLegacyPassPass(PassRegistry&); void initializeCFGPrinterLegacyPassPass(PassRegistry&); diff --git a/include/llvm/Transforms/Scalar.h b/include/llvm/Transforms/Scalar.h index 9019c3be494..8fcf9296ba4 100644 --- a/include/llvm/Transforms/Scalar.h +++ b/include/llvm/Transforms/Scalar.h @@ -471,6 +471,7 @@ FunctionPass *createLoopDataPrefetchPass(); ///===---------------------------------------------------------------------===// ModulePass *createNameAnonGlobalPass(); +ModulePass *createCanonicalizeAliasesPass(); //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Transforms/Utils/CanonicalizeAliases.h b/include/llvm/Transforms/Utils/CanonicalizeAliases.h new file mode 100644 index 00000000000..f23263783fe --- /dev/null +++ b/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 diff --git a/lib/Passes/PassBuilder.cpp b/lib/Passes/PassBuilder.cpp index 2f567262fbb..e1d0a47fb6d 100644 --- a/lib/Passes/PassBuilder.cpp +++ b/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" diff --git a/lib/Passes/PassRegistry.def b/lib/Passes/PassRegistry.def index 2d5fc2e99b1..f20b597a8f0 100644 --- a/lib/Passes/PassRegistry.def +++ b/lib/Passes/PassRegistry.def @@ -42,6 +42,7 @@ MODULE_ALIAS_ANALYSIS("globals-aa", GlobalsAA()) #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()) diff --git a/lib/Transforms/IPO/PassManagerBuilder.cpp b/lib/Transforms/IPO/PassManagerBuilder.cpp index 60bd6def6ce..9764944dc33 100644 --- a/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -462,12 +462,14 @@ void PassManagerBuilder::populateModulePassManager( 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 @@ void PassManagerBuilder::populateModulePassManager( // 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 @@ void PassManagerBuilder::populateModulePassManager( 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) { diff --git a/lib/Transforms/Utils/CMakeLists.txt b/lib/Transforms/Utils/CMakeLists.txt index eb3bad79129..cb3dc17c03a 100644 --- a/lib/Transforms/Utils/CMakeLists.txt +++ b/lib/Transforms/Utils/CMakeLists.txt @@ -6,6 +6,7 @@ add_llvm_library(LLVMTransformUtils BuildLibCalls.cpp BypassSlowDivision.cpp CallPromotionUtils.cpp + CanonicalizeAliases.cpp CloneFunction.cpp CloneModule.cpp CodeExtractor.cpp diff --git a/lib/Transforms/Utils/CanonicalizeAliases.cpp b/lib/Transforms/Utils/CanonicalizeAliases.cpp new file mode 100644 index 00000000000..cf41fd2e14c --- /dev/null +++ b/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 diff --git a/lib/Transforms/Utils/Utils.cpp b/lib/Transforms/Utils/Utils.cpp index afd842f5991..95416de0743 100644 --- a/lib/Transforms/Utils/Utils.cpp +++ b/lib/Transforms/Utils/Utils.cpp @@ -26,6 +26,7 @@ using namespace llvm; void llvm::initializeTransformUtils(PassRegistry &Registry) { initializeAddDiscriminatorsLegacyPassPass(Registry); initializeBreakCriticalEdgesPass(Registry); + initializeCanonicalizeAliasesLegacyPassPass(Registry); initializeInstNamerPass(Registry); initializeLCSSAWrapperPassPass(Registry); initializeLibCallsShrinkWrapLegacyPassPass(Registry); diff --git a/test/Transforms/CanonicalizeAliases/canonicalize.ll b/test/Transforms/CanonicalizeAliases/canonicalize.ll new file mode 100644 index 00000000000..e762fc55953 --- /dev/null +++ b/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)