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