[llvm] 78a65cd - [Passes] Add relative lookup table converter pass

Richard Smith via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 22 17:23:46 PDT 2021


Hi,

This pass has introduced a miscompile that breaks zlib (and therefore also
breaks a from-scratch selfhost). The IR heading into this pass looks like:

@.str = private unnamed_addr constant [16 x i8] c"need dictionary\00",
align 1
@.str.1 = private unnamed_addr constant [11 x i8] c"stream end\00", align 1
@.str.2 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@.str.3 = private unnamed_addr constant [11 x i8] c"file error\00", align 1
@.str.4 = private unnamed_addr constant [13 x i8] c"stream error\00", align
1
@.str.5 = private unnamed_addr constant [11 x i8] c"data error\00", align 1
@.str.6 = private unnamed_addr constant [20 x i8] c"insufficient
memory\00", align 1
@.str.7 = private unnamed_addr constant [13 x i8] c"buffer error\00", align
1
@.str.8 = private unnamed_addr constant [21 x i8] c"incompatible
version\00", align 1
@z_errmsg = dso_local local_unnamed_addr constant [10 x i8*] [i8*
getelementptr inbounds ([16 x i8], [16 x i8]* @.str, i32 0, i32 0), i8*
getelementptr inbounds ([11 x i8], [11 x i8]* @.str.1, i32 0, i32 0), i8*
getelement
ptr inbounds ([1 x i8], [1 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr
inbounds ([11 x i8], [11 x i8]* @.str.3, i32 0, i32 0), i8* getelementptr
inbounds ([13 x i8], [13 x i8]* @.str.4, i32 0, i32 0), i8* getelementpt
r inbounds ([11 x i8], [11 x i8]* @.str.5, i32 0, i32 0), i8* getelementptr
inbounds ([20 x i8], [20 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr
inbounds ([13 x i8], [13 x i8]* @.str.7, i32 0, i32 0), i8* getelementpt
r inbounds ([21 x i8], [21 x i8]* @.str.8, i32 0, i32 0), i8* getelementptr
inbounds ([1 x i8], [1 x i8]* @.str.2, i32 0, i32 0)], align 16

; Function Attrs: norecurse nounwind readnone uwtable willreturn
define dso_local i8* @zError(i32 %0) local_unnamed_addr #0 align 32 {
  %2 = sub nsw i32 2, %0
  %3 = sext i32 %2 to i64
  %4 = getelementptr inbounds [10 x i8*], [10 x i8*]* @z_errmsg, i64 0, i64
%3
  %5 = load i8*, i8** %4, align 8
  ret i8* %5
}

... and the IR coming out of the pass looks like:

@.str = private unnamed_addr constant [16 x i8] c"need dictionary\00",
align 1
@.str.1 = private unnamed_addr constant [11 x i8] c"stream end\00", align 1
@.str.2 = private unnamed_addr constant [1 x i8] zeroinitializer, align 1
@.str.3 = private unnamed_addr constant [11 x i8] c"file error\00", align 1
@.str.4 = private unnamed_addr constant [13 x i8] c"stream error\00", align
1
@.str.5 = private unnamed_addr constant [11 x i8] c"data error\00", align 1
@.str.6 = private unnamed_addr constant [20 x i8] c"insufficient
memory\00", align 1
@.str.7 = private unnamed_addr constant [13 x i8] c"buffer error\00", align
1
@.str.8 = private unnamed_addr constant [21 x i8] c"incompatible
version\00", align 1
@reltable.zError = dso_local unnamed_addr constant [10 x i32] [i32 trunc
(i64 sub (i64 ptrtoint ([16 x i8]* @.str to i64), i64 ptrtoint ([10 x i32]*
@reltable.zError to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([11 x
i8]* @.str.1 to i64), i64 ptrtoint ([10 x i32]* @reltable.zError to i64))
to i32), i32 trunc (i64 sub (i64 ptrtoint ([1 x i8]* @.str.2 to i64), i64
ptrtoint ([10 x i32]* @reltable.zError to i64)) to i32), i32 trunc (i64 sub
(i64 ptrtoint ([11 x i8]* @.str.3 to i64), i64 ptrtoint ([10 x i32]*
@reltable.zError to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([13 x
i8]* @.str.4 to i64), i64 ptrtoint ([10 x i32]* @reltable.zError to i64))
to i32), i32 trunc (i64 sub (i64 ptrtoint ([11 x i8]* @.str.5 to i64), i64
ptrtoint ([10 x i32]* @reltable.zError to i64)) to i32), i32 trunc (i64 sub
(i64 ptrtoint ([20 x i8]* @.str.6 to i64), i64 ptrtoint ([10 x i32]*
@reltable.zError to i64)) to i32), i32 trunc (i64 sub (i64 ptrtoint ([13 x
i8]* @.str.7 to i64), i64 ptrtoint ([10 x i32]* @reltable.zError to i64))
to i32), i32 trunc (i64 sub (i64 ptrtoint ([21 x i8]* @.str.8 to i64), i64
ptrtoint ([10 x i32]* @reltable.zError to i64)) to i32), i32 trunc (i64 sub
(i64 ptrtoint ([1 x i8]* @.str.2 to i64), i64 ptrtoint ([10 x i32]*
@reltable.zError to i64)) to i32)], align 4

; Function Attrs: norecurse nounwind readnone uwtable willreturn
define dso_local i8* @zError(i32 %0) local_unnamed_addr #0 align 32 {
  %2 = sub nsw i32 2, %0
  %3 = sext i32 %2 to i64
  %4 = shl i64 %3, 2
  %5 = call i8* @llvm.load.relative.i64(i8* bitcast ([10 x i32]*
@reltable.zError to i8*), i64 %4)
  ret i8* %5
}

Note that the pass renamed an external-linkage symbol!

Presumably all that's required is a linkage check somewhere. Please can you
either fix or revert? Thanks!


On Mon, 22 Mar 2021 at 15:09, Gulfem Savrun Yeniceri via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

>
> Author: Gulfem Savrun Yeniceri
> Date: 2021-03-22T22:09:02Z
> New Revision: 78a65cd945d006ff02f9d24d9cc20a302ed93b08
>
> URL:
> https://github.com/llvm/llvm-project/commit/78a65cd945d006ff02f9d24d9cc20a302ed93b08
> DIFF:
> https://github.com/llvm/llvm-project/commit/78a65cd945d006ff02f9d24d9cc20a302ed93b08.diff
>
> LOG: [Passes] Add relative lookup table converter pass
>
> Lookup tables generate non PIC-friendly code, which requires dynamic
> relocation as described in:
> https://bugs.llvm.org/show_bug.cgi?id=45244
>
> This patch adds a new pass that converts lookup tables to relative lookup
> tables to make them PIC-friendly.
>
> Differential Revision: https://reviews.llvm.org/D94355
>
> Added:
>     llvm/include/llvm/Transforms/Utils/RelLookupTableConverter.h
>     llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
>
> llvm/test/Transforms/RelLookupTableConverter/X86/no_relative_lookup_table.ll
>
> llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
>
> Modified:
>     llvm/docs/Passes.rst
>     llvm/include/llvm/Analysis/TargetTransformInfo.h
>     llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
>     llvm/include/llvm/CodeGen/BasicTTIImpl.h
>     llvm/include/llvm/InitializePasses.h
>     llvm/include/llvm/Transforms/Scalar.h
>     llvm/lib/Analysis/TargetTransformInfo.cpp
>     llvm/lib/Passes/PassBuilder.cpp
>     llvm/lib/Passes/PassRegistry.def
>     llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
>     llvm/lib/Transforms/Utils/CMakeLists.txt
>     llvm/lib/Transforms/Utils/Utils.cpp
>     llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
>     llvm/test/Other/new-pm-defaults.ll
>     llvm/test/Other/new-pm-thinlto-defaults.ll
>     llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
>     llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
>     llvm/test/Other/opt-O2-pipeline.ll
>     llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
>     llvm/test/Other/opt-O3-pipeline.ll
>     llvm/test/Other/opt-Os-pipeline.ll
>     llvm/test/Other/pass-pipelines.ll
>     llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
>
> Removed:
>
>
>
>
> ################################################################################
> diff  --git a/llvm/docs/Passes.rst b/llvm/docs/Passes.rst
> index 869408fbdf32..5b17983377e4 100644
> --- a/llvm/docs/Passes.rst
> +++ b/llvm/docs/Passes.rst
> @@ -973,6 +973,11 @@ corresponding to the reverse post order traversal of
> current function (starting
>  at 2), which effectively gives values in deep loops higher rank than
> values not
>  in loops.
>
> +``-rel-lookup-table-converter``: Relative lookup table converter
> +-----------------------------------------
> +
> +This pass converts lookup tables to PIC-friendly relative lookup tables.
> +
>  ``-reg2mem``: Demote all values to stack slots
>  ----------------------------------------------
>
>
> diff  --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h
> b/llvm/include/llvm/Analysis/TargetTransformInfo.h
> index dad1381ea8b8..f96f61f8b88d 100644
> --- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
> +++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
> @@ -720,6 +720,9 @@ class TargetTransformInfo {
>    /// containing this constant value for the target.
>    bool shouldBuildLookupTablesForConstant(Constant *C) const;
>
> +  /// Return true if lookup tables should be turned into relative lookup
> tables.
> +  bool shouldBuildRelLookupTables() const;
> +
>    /// Return true if the input function which is cold at all call sites,
>    ///  should use coldcc calling convention.
>    bool useColdCCForColdCall(Function &F) const;
> @@ -1481,6 +1484,7 @@ class TargetTransformInfo::Concept {
>    virtual unsigned getRegUsageForType(Type *Ty) = 0;
>    virtual bool shouldBuildLookupTables() = 0;
>    virtual bool shouldBuildLookupTablesForConstant(Constant *C) = 0;
> +  virtual bool shouldBuildRelLookupTables() = 0;
>    virtual bool useColdCCForColdCall(Function &F) = 0;
>    virtual unsigned getScalarizationOverhead(VectorType *Ty,
>                                              const APInt &DemandedElts,
> @@ -1867,6 +1871,9 @@ class TargetTransformInfo::Model final : public
> TargetTransformInfo::Concept {
>    bool shouldBuildLookupTablesForConstant(Constant *C) override {
>      return Impl.shouldBuildLookupTablesForConstant(C);
>    }
> +  bool shouldBuildRelLookupTables() override {
> +    return Impl.shouldBuildRelLookupTables();
> +  }
>    bool useColdCCForColdCall(Function &F) override {
>      return Impl.useColdCCForColdCall(F);
>    }
>
> diff  --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
> b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
> index 4cf5337de8cf..be3df7294d26 100644
> --- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
> +++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
> @@ -292,8 +292,11 @@ class TargetTransformInfoImplBase {
>    unsigned getRegUsageForType(Type *Ty) const { return 1; }
>
>    bool shouldBuildLookupTables() const { return true; }
> +
>    bool shouldBuildLookupTablesForConstant(Constant *C) const { return
> true; }
>
> +  bool shouldBuildRelLookupTables() const { return true; }
> +
>    bool useColdCCForColdCall(Function &F) const { return false; }
>
>    unsigned getScalarizationOverhead(VectorType *Ty, const APInt
> &DemandedElts,
>
> diff  --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
> b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
> index 9b043fe98b2d..be9388e0c983 100644
> --- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
> +++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
> @@ -45,6 +45,7 @@
>  #include "llvm/Support/ErrorHandling.h"
>  #include "llvm/Support/MachineValueType.h"
>  #include "llvm/Support/MathExtras.h"
> +#include "llvm/Target/TargetMachine.h"
>  #include <algorithm>
>  #include <cassert>
>  #include <cstdint>
> @@ -379,6 +380,25 @@ class BasicTTIImplBase : public
> TargetTransformInfoImplCRTPBase<T> {
>             TLI->isOperationLegalOrCustom(ISD::BRIND, MVT::Other);
>    }
>
> +  bool shouldBuildRelLookupTables() {
> +    const TargetMachine &TM = getTLI()->getTargetMachine();
> +    // If non-PIC mode, do not generate a relative lookup table.
> +    if (!TM.isPositionIndependent())
> +      return false;
> +
> +    if (!TM.getTargetTriple().isArch64Bit())
> +      return false;
> +
> +    /// Relative lookup table entries consist of 32-bit offsets.
> +    /// Do not generate relative lookup tables for large code models
> +    /// in 64-bit achitectures where 32-bit offsets might not be enough.
> +    if (TM.getCodeModel() == CodeModel::Medium ||
> +        TM.getCodeModel() == CodeModel::Large)
> +      return false;
> +
> +    return true;
> +  }
> +
>    bool haveFastSqrt(Type *Ty) {
>      const TargetLoweringBase *TLI = getTLI();
>      EVT VT = TLI->getValueType(DL, Ty);
>
> diff  --git a/llvm/include/llvm/InitializePasses.h
> b/llvm/include/llvm/InitializePasses.h
> index 085cf5fe340e..d786e69295d6 100644
> --- a/llvm/include/llvm/InitializePasses.h
> +++ b/llvm/include/llvm/InitializePasses.h
> @@ -318,6 +318,7 @@ void initializeModuloScheduleTestPass(PassRegistry&);
>  void initializeMustExecutePrinterPass(PassRegistry&);
>  void initializeMustBeExecutedContextPrinterPass(PassRegistry&);
>  void initializeNameAnonGlobalLegacyPassPass(PassRegistry&);
> +void initializeRelLookupTableConverterLegacyPassPass(PassRegistry &);
>  void initializeNaryReassociateLegacyPassPass(PassRegistry&);
>  void initializeNewGVNLegacyPassPass(PassRegistry&);
>  void initializeObjCARCAAWrapperPassPass(PassRegistry&);
>
> diff  --git a/llvm/include/llvm/Transforms/Scalar.h
> b/llvm/include/llvm/Transforms/Scalar.h
> index 3db1613d7457..529133877f1c 100644
> --- a/llvm/include/llvm/Transforms/Scalar.h
> +++ b/llvm/include/llvm/Transforms/Scalar.h
> @@ -517,6 +517,7 @@ FunctionPass *createLoopDataPrefetchPass();
>
>
>  ///===---------------------------------------------------------------------===//
>  ModulePass *createNameAnonGlobalPass();
> +ModulePass *createRelLookupTableConverterPass();
>  ModulePass *createCanonicalizeAliasesPass();
>
>
>  //===----------------------------------------------------------------------===//
>
> diff  --git a/llvm/include/llvm/Transforms/Utils/RelLookupTableConverter.h
> b/llvm/include/llvm/Transforms/Utils/RelLookupTableConverter.h
> new file mode 100644
> index 000000000000..54c257383fb5
> --- /dev/null
> +++ b/llvm/include/llvm/Transforms/Utils/RelLookupTableConverter.h
> @@ -0,0 +1,70 @@
> +//===-- RelLookupTableConverterPass.h - Rel Table Conv ----------*- C++
> -*-===//
> +//
> +// 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
> +//
>
> +//===----------------------------------------------------------------------===//
> +//
> +/// \file
> +/// This file implements relative lookup table converter that converts
> +/// lookup tables to relative lookup tables to make them PIC-friendly.
> +///
> +/// Switch lookup table example:
> +/// @switch.table.foo = private unnamed_addr constant [3 x i8*]
> +/// [
> +/// i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64 0, i64 0),
> +/// i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i64 0, i64
> 0),
> +/// i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2, i64 0, i64 0)
> +/// ], align 8
> +///
> +/// switch.lookup:
> +///   %1 = sext i32 %cond to i64
> +///   %switch.gep = getelementptr inbounds [3 x i8*],
> +///                 [3 x i8*]* @switch.table.foo, i64 0, i64 %1
> +///   %switch.load = load i8*, i8** %switch.gep, align 8
> +///  ret i8* %switch.load
> +///
> +/// Switch lookup table will become a relative lookup table that
> +/// consists of relative offsets.
> +///
> +/// @reltable.foo = private unnamed_addr constant [3 x i32]
> +/// [
> +/// i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64),
> +///                     i64 ptrtoint ([3 x i32]* @reltable.foo to i64))
> to i32),
> +/// i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.1 to i64),
> +///                     i64 ptrtoint ([3 x i32]* @reltable.foo to i64))
> to i32),
> +/// i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to i64),
> +///                     i64 ptrtoint ([3 x i32]* @reltable.foo to i64))
> to i32)
> +/// ], align 4
> +///
> +/// IR after converting to a relative lookup table:
> +/// switch.lookup:
> +///  %1 = sext i32 %cond to i64
> +///  %reltable.shift = shl i64 %1, 2
> +///  %reltable.intrinsic = call i8* @llvm.load.relative.i64(
> +///                        i8* bitcast ([3 x i32]* @reltable.foo to i8*),
> +///                        i64 %reltable.shift)
> +///  ret i8* %reltable.intrinsic
>
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_TRANSFORMS_UTILS_RELLOOKUPTABLECONVERTER_H
> +#define LLVM_TRANSFORMS_UTILS_RELLOOKUPTABLECONVERTER_H
> +
> +#include "llvm/IR/Module.h"
> +#include "llvm/IR/PassManager.h"
> +
> +namespace llvm {
> +
> +// Pass that converts lookup tables to relative lookup tables.
> +class RelLookupTableConverterPass
> +    : public PassInfoMixin<RelLookupTableConverterPass> {
> +public:
> +  RelLookupTableConverterPass() = default;
> +
> +  PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
> +};
> +
> +} // end namespace llvm
> +
> +#endif // LLVM_TRANSFORMS_UTILS_RELLOOKUPTABLECONVERTER_H
>
> diff  --git a/llvm/lib/Analysis/TargetTransformInfo.cpp
> b/llvm/lib/Analysis/TargetTransformInfo.cpp
> index 37da50f8015c..f526d9275cd0 100644
> --- a/llvm/lib/Analysis/TargetTransformInfo.cpp
> +++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
> @@ -456,11 +456,16 @@ unsigned
> TargetTransformInfo::getRegUsageForType(Type *Ty) const {
>  bool TargetTransformInfo::shouldBuildLookupTables() const {
>    return TTIImpl->shouldBuildLookupTables();
>  }
> +
>  bool TargetTransformInfo::shouldBuildLookupTablesForConstant(
>      Constant *C) const {
>    return TTIImpl->shouldBuildLookupTablesForConstant(C);
>  }
>
> +bool TargetTransformInfo::shouldBuildRelLookupTables() const {
> +  return TTIImpl->shouldBuildRelLookupTables();
> +}
> +
>  bool TargetTransformInfo::useColdCCForColdCall(Function &F) const {
>    return TTIImpl->useColdCCForColdCall(F);
>  }
>
> diff  --git a/llvm/lib/Passes/PassBuilder.cpp
> b/llvm/lib/Passes/PassBuilder.cpp
> index 3a325277e370..481995a7d96d 100644
> --- a/llvm/lib/Passes/PassBuilder.cpp
> +++ b/llvm/lib/Passes/PassBuilder.cpp
> @@ -227,6 +227,7 @@
>  #include "llvm/Transforms/Utils/Mem2Reg.h"
>  #include "llvm/Transforms/Utils/MetaRenamer.h"
>  #include "llvm/Transforms/Utils/NameAnonGlobals.h"
> +#include "llvm/Transforms/Utils/RelLookupTableConverter.h"
>  #include "llvm/Transforms/Utils/StripGCRelocates.h"
>  #include "llvm/Transforms/Utils/StripNonLineTableDebugInfo.h"
>  #include "llvm/Transforms/Utils/SymbolRewriter.h"
> @@ -1408,6 +1409,8 @@
> PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level,
>    MPM.addPass(GlobalDCEPass());
>    MPM.addPass(ConstantMergePass());
>
> +  MPM.addPass(RelLookupTableConverterPass());
> +
>    return MPM;
>  }
>
>
> diff  --git a/llvm/lib/Passes/PassRegistry.def
> b/llvm/lib/Passes/PassRegistry.def
> index 579143d3c1c8..72441c9a70b5 100644
> --- a/llvm/lib/Passes/PassRegistry.def
> +++ b/llvm/lib/Passes/PassRegistry.def
> @@ -63,8 +63,8 @@ MODULE_PASS("khwasan", HWAddressSanitizerPass(true,
> true))
>  MODULE_PASS("inferattrs", InferFunctionAttrsPass())
>  MODULE_PASS("inliner-wrapper", ModuleInlinerWrapperPass())
>  MODULE_PASS("inliner-wrapper-no-mandatory-first",
> ModuleInlinerWrapperPass(
> -  getInlineParams(),
> -  DebugLogging,
> +  getInlineParams(),
> +  DebugLogging,
>    false))
>  MODULE_PASS("insert-gcov-profiling", GCOVProfilerPass())
>  MODULE_PASS("instrorderfile", InstrOrderFilePass())
> @@ -93,6 +93,7 @@ MODULE_PASS("print-lcg-dot",
> LazyCallGraphDOTPrinterPass(dbgs()))
>  MODULE_PASS("print-must-be-executed-contexts",
> MustBeExecutedContextPrinterPass(dbgs()))
>  MODULE_PASS("print-stack-safety", StackSafetyGlobalPrinterPass(dbgs()))
>  MODULE_PASS("print<module-debuginfo>", ModuleDebugInfoPrinterPass(dbgs()))
> +MODULE_PASS("rel-lookup-table-converter", RelLookupTableConverterPass())
>  MODULE_PASS("rewrite-statepoints-for-gc", RewriteStatepointsForGC())
>  MODULE_PASS("rewrite-symbols", RewriteSymbolPass())
>  MODULE_PASS("rpo-function-attrs", ReversePostOrderFunctionAttrsPass())
> @@ -281,7 +282,7 @@ FUNCTION_PASS("print<demanded-bits>",
> DemandedBitsPrinterPass(dbgs()))
>  FUNCTION_PASS("print<domfrontier>", DominanceFrontierPrinterPass(dbgs()))
>  FUNCTION_PASS("print<func-properties>",
> FunctionPropertiesPrinterPass(dbgs()))
>  FUNCTION_PASS("print<inline-cost>",
> InlineCostAnnotationPrinterPass(dbgs()))
> -FUNCTION_PASS("print<inliner-size-estimator>",
> +FUNCTION_PASS("print<inliner-size-estimator>",
>    InlineSizeEstimatorAnalysisPrinterPass(dbgs()))
>  FUNCTION_PASS("print<loops>", LoopPrinterPass(dbgs()))
>  FUNCTION_PASS("print<memoryssa>", MemorySSAPrinterPass(dbgs()))
>
> diff  --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
> b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
> index 109e7c97ff1b..dfd0b556a93b 100644
> --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
> +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp
> @@ -909,6 +909,8 @@ void PassManagerBuilder::populateModulePassManager(
>    // resulted in single-entry-single-exit or empty blocks. Clean up the
> CFG.
>    MPM.add(createCFGSimplificationPass());
>
> +  MPM.add(createRelLookupTableConverterPass());
> +
>    addExtensionsToPM(EP_OptimizerLast, MPM);
>
>    if (PrepareForLTO) {
>
> diff  --git a/llvm/lib/Transforms/Utils/CMakeLists.txt
> b/llvm/lib/Transforms/Utils/CMakeLists.txt
> index 4a0f17739d77..1ce4f8c3aada 100644
> --- a/llvm/lib/Transforms/Utils/CMakeLists.txt
> +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt
> @@ -54,6 +54,7 @@ add_llvm_component_library(LLVMTransformUtils
>    NameAnonGlobals.cpp
>    PredicateInfo.cpp
>    PromoteMemoryToRegister.cpp
> +  RelLookupTableConverter.cpp
>    ScalarEvolutionExpander.cpp
>    StripGCRelocates.cpp
>    SSAUpdater.cpp
>
> diff  --git a/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
> b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
> new file mode 100644
> index 000000000000..a767b97f51ac
> --- /dev/null
> +++ b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
> @@ -0,0 +1,252 @@
> +//===- RelLookupTableConverterPass - Rel Table Conv
> -----------------------===//
> +//
> +// 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 file implements relative lookup table converter that converts
> +// lookup tables to relative lookup tables to make them PIC-friendly.
> +//
>
> +//===----------------------------------------------------------------------===//
> +
> +#include "llvm/Transforms/Utils/RelLookupTableConverter.h"
> +#include "llvm/Analysis/ConstantFolding.h"
> +#include "llvm/Analysis/TargetTransformInfo.h"
> +#include "llvm/IR/BasicBlock.h"
> +#include "llvm/IR/IRBuilder.h"
> +#include "llvm/IR/Instructions.h"
> +#include "llvm/IR/Module.h"
> +#include "llvm/InitializePasses.h"
> +#include "llvm/Pass.h"
> +#include "llvm/Transforms/Utils/BasicBlockUtils.h"
> +
> +using namespace llvm;
> +
> +static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV) {
> +  if (!GV.hasInitializer())
> +    return false;
> +
> +  // If lookup table has more than one user,
> +  // do not generate a relative lookup table.
> +  // This is to simplify the analysis that needs to be done for this pass.
> +  // TODO: Add support for lookup tables with multiple uses.
> +  // For ex, this can happen when a function that uses a lookup table gets
> +  // inlined into multiple call sites.
> +  if (!GV.hasOneUse())
> +    return false;
> +
> +  GetElementPtrInst *GEP =
> +      dyn_cast<GetElementPtrInst>(GV.use_begin()->getUser());
> +  if (!GEP || !GEP->hasOneUse())
> +    return false;
> +
> +  if (!isa<LoadInst>(GEP->use_begin()->getUser()))
> +    return false;
> +
> +  // If the original lookup table is not dso_local,
> +  // do not generate a relative lookup table.
> +  // This optimization creates a relative lookup table that consists of
> +  // offsets between the start of the lookup table and its elements.
> +  // To be able to generate these offsets, relative lookup table
> +  // and its elements should be dso_local, which means that they should
> +  // resolve to symbols within the same linkage unit.
> +  if (!(GV.isDSOLocal() || GV.isImplicitDSOLocal()))
> +    return false;
> +
> +  ConstantArray *Array = dyn_cast<ConstantArray>(GV.getInitializer());
> +  // If values are not pointers, do not generate a relative lookup table.
> +  if (!Array || !Array->getType()->getElementType()->isPointerTy())
> +    return false;
> +
> +  const DataLayout &DL = M.getDataLayout();
> +  for (const Use &Op : Array->operands()) {
> +    Constant *ConstOp = cast<Constant>(&Op);
> +    GlobalValue *GVOp;
> +    APInt Offset;
> +
> +    // If an operand is not a constant offset from a lookup table,
> +    // do not generate a relative lookup table.
> +    if (!IsConstantOffsetFromGlobal(ConstOp, GVOp, Offset, DL))
> +      return false;
> +
> +    // If an operand in the lookup table is not dso_local,
> +    // do not generate a relative lookup table.
> +    if (!(GVOp->isDSOLocal() || GVOp->isImplicitDSOLocal()))
> +      return false;
> +  }
> +
> +  return true;
> +}
> +
> +static GlobalVariable *createRelLookupTable(Function &Func,
> +                                            GlobalVariable &LookupTable) {
> +  Module &M = *Func.getParent();
> +  ConstantArray *LookupTableArr =
> +      cast<ConstantArray>(LookupTable.getInitializer());
> +  unsigned NumElts = LookupTableArr->getType()->getNumElements();
> +  ArrayType *IntArrayTy =
> +      ArrayType::get(Type::getInt32Ty(M.getContext()), NumElts);
> +  GlobalVariable *RelLookupTable = new GlobalVariable(
> +      M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
> +      nullptr, "reltable." + Func.getName());
> +  RelLookupTable->copyAttributesFrom(&LookupTable);
> +
> +  uint64_t Idx = 0;
> +  SmallVector<Constant *, 64> RelLookupTableContents(NumElts);
> +
> +  for (Use &Operand : LookupTableArr->operands()) {
> +    Constant *Element = cast<Constant>(Operand);
> +    Type *IntPtrTy = M.getDataLayout().getIntPtrType(M.getContext());
> +    Constant *Base = llvm::ConstantExpr::getPtrToInt(RelLookupTable,
> IntPtrTy);
> +    Constant *Target = llvm::ConstantExpr::getPtrToInt(Element, IntPtrTy);
> +    Constant *Sub = llvm::ConstantExpr::getSub(Target, Base);
> +    Constant *RelOffset =
> +        llvm::ConstantExpr::getTrunc(Sub,
> Type::getInt32Ty(M.getContext()));
> +    RelLookupTableContents[Idx++] = RelOffset;
> +  }
> +
> +  Constant *Initializer =
> +      ConstantArray::get(IntArrayTy, RelLookupTableContents);
> +  RelLookupTable->setInitializer(Initializer);
> +  RelLookupTable->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
> +  RelLookupTable->setAlignment(llvm::Align(4));
> +  return RelLookupTable;
> +}
> +
> +static void convertToRelLookupTable(GlobalVariable &LookupTable) {
> +  GetElementPtrInst *GEP =
> +      cast<GetElementPtrInst>(LookupTable.use_begin()->getUser());
> +  LoadInst *Load = cast<LoadInst>(GEP->use_begin()->getUser());
> +
> +  Module &M = *LookupTable.getParent();
> +  BasicBlock *BB = GEP->getParent();
> +  IRBuilder<> Builder(BB);
> +  Function &Func = *BB->getParent();
> +
> +  // Generate an array that consists of relative offsets.
> +  GlobalVariable *RelLookupTable = createRelLookupTable(Func,
> LookupTable);
> +
> +  // Place new instruction sequence after GEP.
> +  Builder.SetInsertPoint(GEP);
> +  Value *Index = GEP->getOperand(2);
> +  IntegerType *IntTy = cast<IntegerType>(Index->getType());
> +  Value *Offset =
> +      Builder.CreateShl(Index, ConstantInt::get(IntTy, 2),
> "reltable.shift");
> +
> +  Function *LoadRelIntrinsic = llvm::Intrinsic::getDeclaration(
> +      &M, Intrinsic::load_relative, {Index->getType()});
> +  Value *Base = Builder.CreateBitCast(RelLookupTable,
> Builder.getInt8PtrTy());
> +
> +  // Create a call to load.relative intrinsic that computes the target
> address
> +  // by adding base address (lookup table address) and relative offset.
> +  Value *Result = Builder.CreateCall(LoadRelIntrinsic, {Base, Offset},
> +                                     "reltable.intrinsic");
> +
> +  // Create a bitcast instruction if necessary.
> +  if (Load->getType() != Builder.getInt8PtrTy())
> +    Result = Builder.CreateBitCast(Result, Load->getType(),
> "reltable.bitcast");
> +
> +  // Replace load instruction with the new generated instruction sequence.
> +  BasicBlock::iterator InsertPoint(Load);
> +  ReplaceInstWithValue(Load->getParent()->getInstList(), InsertPoint,
> Result);
> +
> +  // Remove GEP instruction.
> +  GEP->eraseFromParent();
> +}
> +
> +// Convert lookup tables to relative lookup tables in the module.
> +static bool convertToRelativeLookupTables(
> +    Module &M, function_ref<TargetTransformInfo &(Function &)> GetTTI) {
> +  Module::iterator FI = M.begin();
> +  if (FI == M.end())
> +    return false;
> +
> +  // Check if we have a target that supports relative lookup tables.
> +  if (!GetTTI(*FI).shouldBuildRelLookupTables())
> +    return false;
> +
> +  bool Changed = false;
> +
> +  for (auto GVI = M.global_begin(), E = M.global_end(); GVI != E;) {
> +    GlobalVariable &GlobalVar = *GVI++;
> +
> +    if (!shouldConvertToRelLookupTable(M, GlobalVar))
> +      continue;
> +
> +    convertToRelLookupTable(GlobalVar);
> +
> +    // Remove the original lookup table.
> +    GlobalVar.eraseFromParent();
> +    Changed = true;
> +  }
> +
> +  return Changed;
> +}
> +
> +PreservedAnalyses RelLookupTableConverterPass::run(Module &M,
> +                                                   ModuleAnalysisManager
> &AM) {
> +  FunctionAnalysisManager &FAM =
> +      AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
> +
> +  auto GetTTI = [&](Function &F) -> TargetTransformInfo & {
> +    return FAM.getResult<TargetIRAnalysis>(F);
> +  };
> +
> +  if (!convertToRelativeLookupTables(M, GetTTI))
> +    return PreservedAnalyses::all();
> +
> +  PreservedAnalyses PA;
> +  PA.preserveSet<CFGAnalyses>();
> +  return PA;
> +}
> +
> +namespace {
> +
> +/// Pass that converts lookup tables to relative lookup tables.
> +class RelLookupTableConverterLegacyPass : public ModulePass {
> +
> +public:
> +  /// Pass identification, replacement for typeid
> +  static char ID;
> +
> +  /// Specify pass name for debug output
> +  StringRef getPassName() const override {
> +    return "Relative Lookup Table Converter";
> +  }
> +
> +  RelLookupTableConverterLegacyPass() : ModulePass(ID) {
> +    initializeRelLookupTableConverterLegacyPassPass(
> +        *PassRegistry::getPassRegistry());
> +  }
> +
> +  bool runOnModule(Module &M) override {
> +    auto GetTTI = [this](Function &F) -> TargetTransformInfo & {
> +      return
> this->getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
> +    };
> +    return convertToRelativeLookupTables(M, GetTTI);
> +  }
> +
> +  void getAnalysisUsage(AnalysisUsage &AU) const override {
> +    AU.addRequired<TargetTransformInfoWrapperPass>();
> +  }
> +};
> +
> +} // anonymous namespace
> +
> +char RelLookupTableConverterLegacyPass::ID = 0;
> +
> +INITIALIZE_PASS_BEGIN(RelLookupTableConverterLegacyPass,
> +                      "rel-lookup-table-converter",
> +                      "Convert to relative lookup tables", false, false)
> +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
> +INITIALIZE_PASS_END(RelLookupTableConverterLegacyPass,
> +                    "rel-lookup-table-converter",
> +                    "Convert to relative lookup tables", false, false)
> +
> +namespace llvm {
> +ModulePass *createRelLookupTableConverterPass() {
> +  return new RelLookupTableConverterLegacyPass();
> +}
> +} // end namespace llvm
>
> diff  --git a/llvm/lib/Transforms/Utils/Utils.cpp
> b/llvm/lib/Transforms/Utils/Utils.cpp
> index 3ca36a1cad91..8d89d3fd617e 100644
> --- a/llvm/lib/Transforms/Utils/Utils.cpp
> +++ b/llvm/lib/Transforms/Utils/Utils.cpp
> @@ -37,6 +37,7 @@ void llvm::initializeTransformUtils(PassRegistry
> &Registry) {
>    initializeLowerSwitchLegacyPassPass(Registry);
>    initializeNameAnonGlobalLegacyPassPass(Registry);
>    initializePromoteLegacyPassPass(Registry);
> +  initializeRelLookupTableConverterLegacyPassPass(Registry);
>    initializeStripNonLineTableDebugLegacyPassPass(Registry);
>    initializeUnifyFunctionExitNodesLegacyPassPass(Registry);
>    initializeMetaRenamerPass(Registry);
>
> diff  --git a/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
> b/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
> index 34e5e6c647da..844f61b200e2 100644
> --- a/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
> +++ b/llvm/test/CodeGen/AMDGPU/opt-pipeline.ll
> @@ -306,6 +306,8 @@
>  ; GCN-O1-NEXT:       Remove redundant instructions
>  ; GCN-O1-NEXT:       Hoist/decompose integer division and remainder
>  ; GCN-O1-NEXT:       Simplify the CFG
> +; GCN-O1-NEXT:     Relative Lookup Table Converter
> +; GCN-O1-NEXT:     FunctionPass Manager
>  ; GCN-O1-NEXT:       Annotation Remarks
>
>  ; GCN-O1-NEXT: Pass Arguments:
> @@ -660,6 +662,8 @@
>  ; GCN-O2-NEXT:       Remove redundant instructions
>  ; GCN-O2-NEXT:       Hoist/decompose integer division and remainder
>  ; GCN-O2-NEXT:       Simplify the CFG
> +; GCN-O2-NEXT:     Relative Lookup Table Converter
> +; GCN-O2-NEXT:     FunctionPass Manager
>  ; GCN-O2-NEXT:       Annotation Remarks
>
>  ; GCN-O2-NEXT: Pass Arguments:
> @@ -1019,6 +1023,8 @@
>  ; GCN-O3-NEXT:       Remove redundant instructions
>  ; GCN-O3-NEXT:       Hoist/decompose integer division and remainder
>  ; GCN-O3-NEXT:       Simplify the CFG
> +; GCN-O3-NEXT:     Relative Lookup Table Converter
> +; GCN-O3-NEXT:     FunctionPass Manager
>  ; GCN-O3-NEXT:       Annotation Remarks
>
>  ; GCN-O3-NEXT: Pass Arguments:
>
> diff  --git a/llvm/test/Other/new-pm-defaults.ll
> b/llvm/test/Other/new-pm-defaults.ll
> index 01b02b8fd482..12d49d15b424 100644
> --- a/llvm/test/Other/new-pm-defaults.ll
> +++ b/llvm/test/Other/new-pm-defaults.ll
> @@ -113,9 +113,9 @@
>  ; CHECK-O-NEXT: Running analysis: CallGraphAnalysis
>  ; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
>  ; CHECK-O-NEXT: Running analysis: ProfileSummaryAnalysis
> -; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
> -; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
> -; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
> +; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
> +; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
> +; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
>  ; CHECK-O-NEXT: Running analysis:
> OuterAnalysisManagerProxy<{{.*}}LazyCallGraph::SCC{{.*}}>
>  ; CHECK-O-NEXT: Running pass: DevirtSCCRepeatedPass
>  ; CHECK-O-NEXT: Starting CGSCC pass manager run.
> @@ -256,6 +256,8 @@
>  ; CHECK-O-NEXT: Running pass: CGProfilePass
>  ; CHECK-O-NEXT: Running pass: GlobalDCEPass
>  ; CHECK-O-NEXT: Running pass: ConstantMergePass
> +; CHECK-O-NEXT: Running pass: RelLookupTableConverterPass
> +; CHECK-O-NEXT: Running analysis: TargetIRAnalysis
>  ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
>  ; CHECK-LTO-NEXT: Running pass: CanonicalizeAliasesPass
>  ; CHECK-LTO-NEXT: Running pass: NameAnonGlobalPass
>
> diff  --git a/llvm/test/Other/new-pm-thinlto-defaults.ll
> b/llvm/test/Other/new-pm-thinlto-defaults.ll
> index fbf47de87eeb..3c7e84798226 100644
> --- a/llvm/test/Other/new-pm-thinlto-defaults.ll
> +++ b/llvm/test/Other/new-pm-thinlto-defaults.ll
> @@ -98,9 +98,9 @@
>  ; CHECK-O-NEXT: Running analysis: CallGraphAnalysis
>  ; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
>  ; CHECK-PRELINK-O-NEXT: Running analysis: ProfileSummaryAnalysis
> -; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
> -; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
> -; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
> +; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
> +; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
> +; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
>  ; CHECK-O-NEXT: Running analysis: OuterAnalysisManagerProxy
>  ; CHECK-O-NEXT: Running pass: DevirtSCCRepeatedPass
>  ; CHECK-O-NEXT: Starting CGSCC pass manager run.
> @@ -243,6 +243,8 @@
>  ; CHECK-POSTLINK-O-NEXT: Running pass: CGProfilePass
>  ; CHECK-POSTLINK-O-NEXT: Running pass: GlobalDCEPass
>  ; CHECK-POSTLINK-O-NEXT: Running pass: ConstantMergePass
> +; CHECK-POSTLINK-O-NEXT: Running pass: RelLookupTableConverterPass
> +; CHECK-POSTLINK-O-NEXT: Running analysis: TargetIRAnalysis
>  ; CHECK-O-NEXT:          Running pass: AnnotationRemarksPass on foo
>  ; CHECK-PRELINK-O-NEXT: Running pass: CanonicalizeAliasesPass
>  ; CHECK-PRELINK-O-NEXT: Running pass: NameAnonGlobalPass
>
> diff  --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
> b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
> index 4bcf70e15a5b..6a067a09c15c 100644
> --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
> +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
> @@ -68,10 +68,10 @@
>  ; CHECK-O-NEXT: Running pass: ModuleInlinerWrapperPass
>  ; CHECK-O-NEXT: Running analysis: InlineAdvisorAnalysis
>  ; CHECK-O-NEXT: Starting {{.*}}Module pass manager run.
> -; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
> -; CHECK-O-NEXT: Running analysis: GlobalsAA
> -; CHECK-O-NEXT: Running analysis: CallGraphAnalysis
> -; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
> +; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
> +; CHECK-O-NEXT: Running analysis: GlobalsAA
> +; CHECK-O-NEXT: Running analysis: CallGraphAnalysis
> +; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
>  ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
>  ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
>  ; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
> @@ -212,6 +212,8 @@
>  ; CHECK-O-NEXT: Running pass: CGProfilePass
>  ; CHECK-O-NEXT: Running pass: GlobalDCEPass
>  ; CHECK-O-NEXT: Running pass: ConstantMergePass
> +; CHECK-O-NEXT: Running pass: RelLookupTableConverterPass
> +; CHECK-O-NEXT: Running analysis: TargetIRAnalysis
>  ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
>  ; CHECK-O-NEXT: Running pass: PrintModulePass
>
>
> diff  --git
> a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
> b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
> index 1071d28432b9..bd4f60a8545a 100644
> --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
> +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll
> @@ -78,9 +78,9 @@
>  ; CHECK-O-NEXT: Running pass: ModuleInlinerWrapperPass
>  ; CHECK-O-NEXT: Running analysis: InlineAdvisorAnalysis
>  ; CHECK-O-NEXT: Starting {{.*}}Module pass manager run.
> -; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
> -; CHECK-O-NEXT: Running analysis: GlobalsAA
> -; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
> +; CHECK-O-NEXT: Running pass: RequireAnalysisPass<{{.*}}GlobalsAA
> +; CHECK-O-NEXT: Running analysis: GlobalsAA
> +; CHECK-O-NEXT: Running pass:
> RequireAnalysisPass<{{.*}}ProfileSummaryAnalysis
>  ; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
>  ; CHECK-O-NEXT: Running analysis: LazyCallGraphAnalysis
>  ; CHECK-O-NEXT: Running analysis: FunctionAnalysisManagerCGSCCProxy
> @@ -224,6 +224,8 @@
>  ; CHECK-O-NEXT: Running pass: CGProfilePass
>  ; CHECK-O-NEXT: Running pass: GlobalDCEPass
>  ; CHECK-O-NEXT: Running pass: ConstantMergePass
> +; CHECK-O-NEXT: Running pass: RelLookupTableConverterPass
> +; CHECK-O-NEXT: Running analysis: TargetIRAnalysis
>  ; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
>  ; CHECK-O-NEXT: Running pass: PrintModulePass
>
>
> diff  --git a/llvm/test/Other/opt-O2-pipeline.ll
> b/llvm/test/Other/opt-O2-pipeline.ll
> index f7217c122fdb..ab0a5c9724b1 100644
> --- a/llvm/test/Other/opt-O2-pipeline.ll
> +++ b/llvm/test/Other/opt-O2-pipeline.ll
> @@ -307,6 +307,8 @@
>  ; CHECK-NEXT:       Remove redundant instructions
>  ; CHECK-NEXT:       Hoist/decompose integer division and remainder
>  ; CHECK-NEXT:       Simplify the CFG
> +; CHECK-NEXT:     Relative Lookup Table Converter
> +; CHECK-NEXT:     FunctionPass Manager
>  ; CHECK-NEXT:       Annotation Remarks
>  ; CHECK-NEXT:       Module Verifier
>  ; CHECK-NEXT:     Bitcode Writer
>
> diff  --git a/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
> b/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
> index 6b98c1f80d9e..6bcebfcb4206 100644
> --- a/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
> +++ b/llvm/test/Other/opt-O3-pipeline-enable-matrix.ll
> @@ -319,6 +319,8 @@
>  ; CHECK-NEXT:       Remove redundant instructions
>  ; CHECK-NEXT:       Hoist/decompose integer division and remainder
>  ; CHECK-NEXT:       Simplify the CFG
> +; CHECK-NEXT:     Relative Lookup Table Converter
> +; CHECK-NEXT:     FunctionPass Manager
>  ; CHECK-NEXT:       Annotation Remarks
>  ; CHECK-NEXT:       Module Verifier
>  ; CHECK-NEXT:     Bitcode Writer
>
> diff  --git a/llvm/test/Other/opt-O3-pipeline.ll
> b/llvm/test/Other/opt-O3-pipeline.ll
> index 00a1d61ac058..bd692f255954 100644
> --- a/llvm/test/Other/opt-O3-pipeline.ll
> +++ b/llvm/test/Other/opt-O3-pipeline.ll
> @@ -312,6 +312,8 @@
>  ; CHECK-NEXT:       Remove redundant instructions
>  ; CHECK-NEXT:       Hoist/decompose integer division and remainder
>  ; CHECK-NEXT:       Simplify the CFG
> +; CHECK-NEXT:     Relative Lookup Table Converter
> +; CHECK-NEXT:     FunctionPass Manager
>  ; CHECK-NEXT:       Annotation Remarks
>  ; CHECK-NEXT:       Module Verifier
>  ; CHECK-NEXT:     Bitcode Writer
>
> diff  --git a/llvm/test/Other/opt-Os-pipeline.ll
> b/llvm/test/Other/opt-Os-pipeline.ll
> index 21f9b8c6009e..496e928b8014 100644
> --- a/llvm/test/Other/opt-Os-pipeline.ll
> +++ b/llvm/test/Other/opt-Os-pipeline.ll
> @@ -293,6 +293,8 @@
>  ; CHECK-NEXT:       Remove redundant instructions
>  ; CHECK-NEXT:       Hoist/decompose integer division and remainder
>  ; CHECK-NEXT:       Simplify the CFG
> +; CHECK-NEXT:     Relative Lookup Table Converter
> +; CHECK-NEXT:     FunctionPass Manager
>  ; CHECK-NEXT:       Annotation Remarks
>  ; CHECK-NEXT:       Module Verifier
>  ; CHECK-NEXT:     Bitcode Writer
>
> diff  --git a/llvm/test/Other/pass-pipelines.ll
> b/llvm/test/Other/pass-pipelines.ll
> index ccd364d5d740..c1a24a366d7e 100644
> --- a/llvm/test/Other/pass-pipelines.ll
> +++ b/llvm/test/Other/pass-pipelines.ll
> @@ -106,6 +106,8 @@
>  ; CHECK-O2: Loop Pass Manager
>  ; CHECK-O2-NEXT: Loop Sink
>  ; CHECK-O2: Simplify the CFG
> +; CHECK-O2: Relative Lookup Table Converter
> +; CHECK-O2: FunctionPass Manager
>  ; CHECK-O2-NOT: Manager
>  ;
>  ; FIXME: There really shouldn't be another pass manager, especially one
> that
>
> diff  --git
> a/llvm/test/Transforms/RelLookupTableConverter/X86/no_relative_lookup_table.ll
> b/llvm/test/Transforms/RelLookupTableConverter/X86/no_relative_lookup_table.ll
> new file mode 100644
> index 000000000000..4a5c04f864b0
> --- /dev/null
> +++
> b/llvm/test/Transforms/RelLookupTableConverter/X86/no_relative_lookup_table.ll
> @@ -0,0 +1,57 @@
> +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
> +; RUN: opt < %s -rel-lookup-table-converter -mtriple=x86_64-linux -S |
> FileCheck %s
> +; RUN: opt < %s -rel-lookup-table-converter -mtriple=i386-unknown-unknown
> -relocation-model=pic -S | FileCheck %s
> +; RUN: opt < %s -rel-lookup-table-converter -mtriple=x86_64-linux
> -relocation-model=pic -code-model=medium -S | FileCheck %s
> +; RUN: opt < %s -rel-lookup-table-converter -mtriple=x86_64-linux
> -relocation-model=pic -code-model=large -S | FileCheck %s
> +
> +; RUN: opt < %s -passes=rel-lookup-table-converter -mtriple=x86_64-linux
> -S | FileCheck %s
> +; RUN: opt < %s -passes=rel-lookup-table-converter
> -mtriple=i386-unknown-unknown -relocation-model=pic -S | FileCheck %s
> +; RUN: opt < %s -passes=rel-lookup-table-converter -mtriple=x86_64-linux
> -relocation-model=pic -code-model=medium -S | FileCheck %s
> +; RUN: opt < %s -passes=rel-lookup-table-converter -mtriple=x86_64-linux
> -relocation-model=pic -code-model=large -S | FileCheck %s
> +target datalayout =
> "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
> +
> + at .str = private unnamed_addr constant [5 x i8] c"zero\00", align 1
> + at .str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1
> + at .str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1
> + at .str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1
> +
> + at switch.table.string_table = private unnamed_addr constant [3 x i8*]
> +                             [
> +                              i8* getelementptr inbounds ([5 x i8], [5 x
> i8]* @.str, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.1, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.2, i64 0, i64 0)
> +                             ], align 8
> +
> +; Switch lookup table
> +; CHECK: @switch.table.string_table = private unnamed_addr constant [3 x
> i8*]
> +; CHECK-SAME: [
> +; CHECK-SAME: i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str, i64
> 0, i64 0),
> +; CHECK-SAME: i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1,
> i64 0, i64 0),
> +; CHECK-SAME: i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.2,
> i64 0, i64 0)
> +; CHECK-SAME: ], align 8
> +
> +; ; Relative switch lookup table for strings
> +define i8* @string_table(i32 %cond) {
> +  ; CHECK-LABEL: @string_table(
> +  ; CHECK-NEXT:  entry:
> +  ; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +  ; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +  ; CHECK:       switch.lookup:
> +  ; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i8*],
> [3 x i8*]* @switch.table.string_table, i32 0, i32 [[COND]]
> +  ; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i8*, i8** [[SWITCH_GEP]],
> align 8
> +  ; CHECK-NEXT:    ret i8* [[SWITCH_LOAD]]
> +  ; CHECK:       return:
> +  ; CHECK-NEXT:    ret i8* getelementptr inbounds ([8 x i8], [8 x i8]*
> @.str.3, i64 0, i64 0)
> +
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i8*], [3 x i8*]*
> @switch.table.string_table, i32 0, i32 %cond
> +  %switch.load = load i8*, i8** %switch.gep, align 8
> +  ret i8* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64
> 0)
> +}
>
> diff  --git
> a/llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
> b/llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
> new file mode 100644
> index 000000000000..9129c5532e06
> --- /dev/null
> +++
> b/llvm/test/Transforms/RelLookupTableConverter/X86/relative_lookup_table.ll
> @@ -0,0 +1,310 @@
> +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
> +; RUN: opt < %s -rel-lookup-table-converter -relocation-model=pic -S |
> FileCheck %s
> +; RUN: opt < %s -passes=rel-lookup-table-converter -relocation-model=pic
> -S | FileCheck %s
> +target datalayout =
> "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
> +target triple = "x86_64-unknown-linux-gnu"
> +
> + at .str = private unnamed_addr constant [5 x i8] c"zero\00", align 1
> + at .str.1 = private unnamed_addr constant [4 x i8] c"one\00", align 1
> + at .str.2 = private unnamed_addr constant [4 x i8] c"two\00", align 1
> + at .str.3 = private unnamed_addr constant [8 x i8] c"default\00", align 1
> + at .str.4 = private unnamed_addr constant [6 x i8] c"three\00", align 1
> + at .str.5 = private unnamed_addr constant [5 x i8] c"str1\00", align 1
> + at .str.6 = private unnamed_addr constant [5 x i8] c"str2\00", align 1
> + at .str.7 = private unnamed_addr constant [12 x i8] c"singlevalue\00",
> align 1
> +
> + at a1 = external global i32, align 4
> + at b1 = external global i32, align 4
> + at c1 = external global i32, align 4
> + at d1 = external global i32, align 4
> +
> + at a2 = internal global i32 0, align 4
> + at b2 = internal global i32 0, align 4
> + at c2 = internal global i32 0, align 4
> + at d2 = internal global i32 0, align 4
> +
> + at hidden0 = external hidden global i32, align 8
> + at hidden1 = external hidden global i32, align 8
> + at hidden2 = external hidden global i32, align 8
> + at hidden3 = external hidden global i32, align 8
> +
> + at switch.table.no_dso_local = private unnamed_addr constant [3 x i32*]
> [i32* @a1, i32* @b1, i32* @c1], align 8
> +
> + at switch.table.dso_local = private unnamed_addr constant [3 x i32*] [i32*
> @a2, i32* @b2, i32* @c2], align 8
> +
> + at switch.table.hidden = private unnamed_addr constant [3 x i32*] [i32*
> @hidden0, i32* @hidden1, i32* @hidden2], align 8
> +
> + at switch.table.string_table = private unnamed_addr constant [3 x i8*]
> +                             [
> +                              i8* getelementptr inbounds ([5 x i8], [5 x
> i8]* @.str, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.1, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.2, i64 0, i64 0)
> +                             ], align 8
> +
> + at switch.table.string_table_holes = private unnamed_addr constant [4 x i8*]
> +                                   [
> +                                    i8* getelementptr inbounds ([5 x i8],
> [5 x i8]* @.str, i64 0, i64 0),
> +                                    i8* getelementptr inbounds ([8 x i8],
> [8 x i8]* @.str.3, i64 0, i64 0),
> +                                    i8* getelementptr inbounds ([4 x i8],
> [4 x i8]* @.str.2, i64 0, i64 0),
> +                                    i8* getelementptr inbounds ([6 x i8],
> [6 x i8]* @.str.4, i64 0, i64 0)
> +                                   ], align 8
> +
> + at switch.table.single_value = private unnamed_addr constant [3 x i8*]
> +                             [
> +                              i8* getelementptr inbounds ([5 x i8], [5 x
> i8]* @.str, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.1, i64 0, i64 0),
> +                              i8* getelementptr inbounds ([4 x i8], [4 x
> i8]* @.str.2, i64 0, i64 0)
> +                             ], align 8
> +
> + at user_defined_lookup_table.table = internal unnamed_addr constant [3 x
> i8*]
> +                                   [
> +                                    i8* getelementptr inbounds ([5 x i8],
> [5 x i8]* @.str, i32 0, i32 0),
> +                                    i8* getelementptr inbounds ([4 x i8],
> [4 x i8]* @.str.1, i32 0, i32 0),
> +                                    i8* getelementptr inbounds ([4 x i8],
> [4 x i8]* @.str.2, i32 0, i32 0)
> +                                   ], align 16
> +
> +; Lookup table for non dso-local integer pointers
> +; CHECK: @switch.table.no_dso_local = private unnamed_addr constant [3 x
> i32*] [i32* @a1, i32* @b1, i32* @c1], align
> +
> +; Relative switch lookup table for dso-local integer pointers
> +; CHECK: @reltable.dso_local = private unnamed_addr constant [3 x i32]
> +; CHECK-SAME: [
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @a2 to i64), i64
> ptrtoint ([3 x i32]* @reltable.dso_local to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @b2 to i64), i64
> ptrtoint ([3 x i32]* @reltable.dso_local to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @c2 to i64), i64
> ptrtoint ([3 x i32]* @reltable.dso_local to i64)) to i32)
> +; CHECK-SAME: ], align 4
> +
> +; Relative switch lookup table for integer pointers with hidden visibility
> +; CHECK: @reltable.hidden = private unnamed_addr constant [3 x i32]
> +; CHECK-SAME: [
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @hidden0 to i64),
> i64 ptrtoint ([3 x i32]* @reltable.hidden to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @hidden1 to i64),
> i64 ptrtoint ([3 x i32]* @reltable.hidden to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (i32* @hidden2 to i64),
> i64 ptrtoint ([3 x i32]* @reltable.hidden to i64)) to i32)
> +; CHECK-SAME: ], align 4
> +
> +; Relative switch lookup table for strings
> +; CHECK: @reltable.string_table = private unnamed_addr constant [3 x i32]
> +; CHECK-SAME: [
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64),
> i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.1 to
> i64), i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to
> i64), i64 ptrtoint ([3 x i32]* @reltable.string_table to i64)) to i32)
> +; CHECK-SAME: ], align 4
> +
> +; Relative switch lookup table for strings with holes, where holes are
> filled with relative offset to default values
> +; CHECK: @reltable.string_table_holes = private unnamed_addr constant [4
> x i32]
> +; CHECK-SAME: [
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64),
> i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([8 x i8]* @.str.3 to
> i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to
> i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to
> i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to
> i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([6 x i8]* @.str.4 to
> i64), i64 ptrtoint ([4 x i32]* @reltable.string_table_holes to i64)) to i32)
> +; CHECK-SAME: ], align 4
> +
> +; Single value check
> +; CHECK: @reltable.single_value = private unnamed_addr constant [3 x i32]
> +; CHECK-SAME: [
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([5 x i8]* @.str to i64),
> i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.1 to
> i64), i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32),
> +; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint ([4 x i8]* @.str.2 to
> i64), i64 ptrtoint ([3 x i32]* @reltable.single_value to i64)) to i32)
> +; CHECK-SAME: ], align 4
> +;
> +
> +; Lookup table check for non dso-local integer pointers
> +define i32* @no_dso_local(i32 %cond) {
> +; CHECK-LABEL: @no_dso_local(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       switch.lookup:
> +; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i32*],
> [3 x i32*]* @switch.table.no_dso_local, i32 0, i32 [[COND:%.*]]
> +; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i32*, i32** [[SWITCH_GEP]],
> align 8
> +; CHECK-NEXT:    ret i32* [[SWITCH_LOAD]]
> +; CHECK:       return:
> +; CHECK-NEXT:    ret i32* @d1
> +;
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i32*], [3 x i32*]*
> @switch.table.no_dso_local, i32 0, i32 %cond
> +  %switch.load = load i32*, i32** %switch.gep, align 8
> +  ret i32* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i32* @d1
> +}
> +
> +; Relative switch lookup table for dso-local integer pointers
> +define i32* @dso_local(i32 %cond) {
> +; CHECK-LABEL: @dso_local(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       switch.lookup:
> +; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 %cond, 2
> +; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.dso_local to
> i8*), i32 [[RELTABLE_SHIFT]])
> +; CHECK-NEXT:    [[BIT_CAST:%.*]] = bitcast i8* [[RELTABLE_INTRINSIC]] to
> i32*
> +; CHECK-NEXT:    ret i32* [[BIT_CAST]]
> +; CHECK:       return:
> +; CHECK-NEXT:    ret i32* @d2
> +;
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i32*], [3 x i32*]*
> @switch.table.dso_local, i32 0, i32 %cond
> +  %switch.load = load i32*, i32** %switch.gep, align 8
> +  ret i32* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i32* @d2
> +}
> +
> +; Relative switch lookup table for integer pointers with hidden visibility
> +define i32* @hidden(i32 %cond) {
> +; CHECK-LABEL: @hidden(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       switch.lookup:
> +; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 %cond, 2
> +; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.hidden to i8*),
> i32 [[RELTABLE_SHIFT]])
> +; CHECK-NEXT:    [[BIT_CAST:%.*]] = bitcast i8* [[RELTABLE_INTRINSIC]] to
> i32*
> +; CHECK-NEXT:    ret i32* [[BIT_CAST]]
> +; CHECK:       return:
> +; CHECK-NEXT:    ret i32* @d2
> +;
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i32*], [3 x i32*]*
> @switch.table.hidden, i32 0, i32 %cond
> +  %switch.load = load i32*, i32** %switch.gep, align 8
> +  ret i32* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i32* @d2
> +}
> +
> +; ; Relative switch lookup table for strings
> +define i8* @string_table(i32 %cond) {
> +  ; CHECK-LABEL: @string_table(
> +  ; CHECK-NEXT:  entry:
> +  ; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +  ; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +  ; CHECK:       switch.lookup:
> +  ; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 %cond, 2
> +  ; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.string_table to
> i8*), i32 [[RELTABLE_SHIFT]])
> +  ; CHECK-NEXT:    ret i8* [[RELTABLE_INTRINSIC]]
> +  ; CHECK:       return:
> +  ; CHECK-NEXT:    ret i8* getelementptr inbounds ([8 x i8], [8 x i8]*
> @.str.3, i64 0, i64 0)
> +  ;
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i8*], [3 x i8*]*
> @switch.table.string_table, i32 0, i32 %cond
> +  %switch.load = load i8*, i8** %switch.gep, align 8
> +  ret i8* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64
> 0)
> +}
> +
> +; Relative switch lookup table for strings with holes, where holes are
> filled with relative offset to default values
> +define i8* @string_table_holes(i32 %cond) {
> +; CHECK-LABEL: @string_table_holes(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 4
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       switch.lookup:
> +; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
> +; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i32(i8* bitcast ([4 x i32]*
> @reltable.string_table_holes to i8*), i32 [[RELTABLE_SHIFT]])
> +; CHECK-NEXT:    ret i8* [[RELTABLE_INTRINSIC]]
> +; CHECK:       return:
> +; CHECK-NEXT:    ret i8* getelementptr inbounds ([8 x i8], [8 x i8]*
> @.str.3, i64 0, i64 0)
> +;
> +entry:
> +  %0 = icmp ult i32 %cond, 4
> +  br i1 %0, label %switch.lookup, label %return
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [4 x i8*], [4 x i8*]*
> @switch.table.string_table_holes, i32 0, i32 %cond
> +  %switch.load = load i8*, i8** %switch.gep, align 8
> +  ret i8* %switch.load
> +
> +return:                                           ; preds = %entry
> +  ret i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64 0, i64
> 0)
> +}
> +
> +
> +; Single value check
> +; If there is a lookup table, where each element contains the same value,
> +; a relative lookup should not be generated
> +define void @single_value(i32 %cond)  {
> +; CHECK-LABEL: @single_value(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp ult i32 [[COND:%.*]], 3
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       switch.lookup:
> +; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i32 [[COND]], 2
> +; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i32(i8* bitcast ([3 x i32]* @reltable.single_value to
> i8*), i32 [[RELTABLE_SHIFT]])
> +; CHECK:       sw.epilog:
> +; CHECK-NEXT:   [[STR1:%.*]] = phi i8* [ getelementptr inbounds ([5 x
> i8], [5 x i8]* @.str.5, i64 0, i64 0), %entry ], [ getelementptr inbounds
> ([12 x i8], [12 x i8]* @.str.7, i64 0, i64 0), %switch.lookup ]
> +; CHECK-NEXT:   [[STR2:%.*]] = phi i8* [ getelementptr inbounds ([5 x
> i8], [5 x i8]* @.str.6, i64 0, i64 0), %entry ], [ [[RELTABLE_INTRINSIC]],
> [[SWITCH_LOOKUP]] ]
> +; CHECK-NEXT:    ret void
> +
> +entry:
> +  %0 = icmp ult i32 %cond, 3
> +  br i1 %0, label %switch.lookup, label %sw.epilog
> +
> +switch.lookup:                                    ; preds = %entry
> +  %switch.gep = getelementptr inbounds [3 x i8*], [3 x i8*]*
> @switch.table.single_value, i32 0, i32 %cond
> +  %switch.load = load i8*, i8** %switch.gep, align 8
> +  br label %sw.epilog
> +
> +sw.epilog:                                        ; preds =
> %switch.lookup, %entry
> +  %str1.0 = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]*
> @.str.5, i64 0, i64 0), %entry ], [ getelementptr inbounds ([12 x i8], [12
> x i8]* @.str.7, i64 0, i64 0), %switch.lookup ]
> +  %str2.0 = phi i8* [ getelementptr inbounds ([5 x i8], [5 x i8]*
> @.str.6, i64 0, i64 0), %entry ], [ %switch.load, %switch.lookup ]
> +  ret void
> +}
> +
> +; Relative lookup table generated for a user-defined lookup table
> +define i8* @user_defined_lookup_table(i32 %cond)  {
> +; CHECK-LABEL: @user_defined_lookup_table(
> +; CHECK-NEXT:  entry:
> +; CHECK-NEXT:    [[TMP0:%.*]] = icmp sgt i32 [[COND:%.*]], 3
> +; CHECK-NEXT:    br i1 [[TMP0]], label [[SWITCH_LOOKUP:%.*]], label
> [[RETURN:%.*]]
> +; CHECK:       cond.false:
> +; CHECK-NEXT:    [[IDX_PROM:%.*]] = sext i32 [[COND]] to i64
> +; CHECK-NEXT:    [[RELTABLE_SHIFT:%.*]] = shl i64 [[IDX_PROM]], 2
> +; CHECK-NEXT:    [[RELTABLE_INTRINSIC:%.*]] = call i8*
> @llvm.load.relative.i64(i8* bitcast ([3 x i32]*
> @reltable.user_defined_lookup_table to i8*), i64 [[RELTABLE_SHIFT]])
> +; CHECK-NEXT:    br label %cond.end
> +; CHECK:       cond.end:
> +; CHECK-NEXT:    [[COND1:%.*]] = phi i8* [ [[RELTABLE_INTRINSIC]],
> %cond.false ], [ getelementptr inbounds ([8 x i8], [8 x i8]* @.str.3, i64
> 0, i64 0), %entry ]
> +; CHECK-NEXT:    ret i8* [[COND1]]
> +;
> +entry:
> +  %cmp = icmp sgt i32 %cond, 3
> +  br i1 %cmp, label %cond.end, label %cond.false
> +
> +cond.false:                                       ; preds = %entry
> +  %idxprom = sext i32 %cond to i64
> +  %arrayidx = getelementptr inbounds [3 x i8*], [3 x i8*]*
> @user_defined_lookup_table.table, i64 0, i64 %idxprom
> +  %0 = load i8*, i8** %arrayidx, align 8, !tbaa !4
> +  br label %cond.end
> +
> +cond.end:                                         ; preds = %entry,
> %cond.false
> +  %cond1 = phi i8* [ %0, %cond.false ], [ getelementptr inbounds ([8 x
> i8], [8 x i8]* @.str.3, i64 0, i64 0), %entry ]
> +  ret i8* %cond1
> +}
> +
> +!llvm.module.flags = !{!0, !1}
> +!0 = !{i32 7, !"PIC Level", i32 2}
> +!1 = !{i32 1, !"Code Model", i32 1}
> +!4 = !{!"any pointer", !5, i64 0}
> +!5 = !{!"omnipotent char", !6, i64 0}
> +!6 = !{!"Simple C/C++ TBAA"}
>
> diff  --git a/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
> b/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
> index 479f7e8e98fc..8268b30b0164 100644
> --- a/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
> +++ b/llvm/utils/gn/secondary/llvm/lib/Transforms/Utils/BUILD.gn
> @@ -61,6 +61,7 @@ static_library("Utils") {
>      "NameAnonGlobals.cpp",
>      "PredicateInfo.cpp",
>      "PromoteMemoryToRegister.cpp",
> +    "RelLookupTableConverter.cpp"
>      "SSAUpdater.cpp",
>      "SSAUpdaterBulk.cpp",
>      "SampleProfileLoaderBaseUtil.cpp",
>
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20210322/f2d91e72/attachment.html>


More information about the llvm-commits mailing list