[llvm] [RelLookupTableConverter] Enable relative lookup tables on Arm. (PR #77910)

Simon Tatham via llvm-commits llvm-commits at lists.llvm.org
Fri Jan 12 03:57:59 PST 2024


https://github.com/statham-arm created https://github.com/llvm/llvm-project/pull/77910

This pass was only enabled for arrays of 64-bit pointers. But 64-bit architectures aren't the only place where you want to turn arrays of absolute pointers into arrays of relative offsets. It's just as useful for making lookup tables PIC-compatible on 32-bit architectures.

In this patch I've enabled it for just the 32-bit Arm architecture, because I know that that has an ELF relocation type (R_ARM_REL32) that makes it possible to express the relative offsets. Possibly it could be enabled for other 32-bit architectures too.

>From 66f42927fdc0cfd3decaf042b74015b8cfc3337f Mon Sep 17 00:00:00 2001
From: Simon Tatham <simon.tatham at arm.com>
Date: Thu, 11 Jan 2024 17:22:29 +0000
Subject: [PATCH] [RelLookupTableConverter] Enable relative lookup tables on
 Arm.

This pass was only enabled for arrays of 64-bit pointers. But 64-bit
architectures aren't the only place where you want to turn arrays of
absolute pointers into arrays of relative offsets. It's just as useful
for making lookup tables PIC-compatible on 32-bit architectures.

In this patch I've enabled it for just the 32-bit Arm architecture,
because I know that that has an ELF relocation type (R_ARM_REL32) that
makes it possible to express the relative offsets. Possibly it could
be enabled for other 32-bit architectures too.
---
 llvm/include/llvm/CodeGen/BasicTTIImpl.h      |  4 +-
 .../Utils/RelLookupTableConverter.cpp         | 25 ++++++++----
 .../ARM/rel_lookup_table.ll                   | 39 +++++++++++++++++++
 3 files changed, 60 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/Transforms/RelLookupTableConverter/ARM/rel_lookup_table.ll

diff --git a/llvm/include/llvm/CodeGen/BasicTTIImpl.h b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
index 5e7bdcdf72a49f..ad043877254984 100644
--- a/llvm/include/llvm/CodeGen/BasicTTIImpl.h
+++ b/llvm/include/llvm/CodeGen/BasicTTIImpl.h
@@ -512,8 +512,10 @@ class BasicTTIImplBase : public TargetTransformInfoImplCRTPBase<T> {
         TM.getCodeModel() == CodeModel::Large)
       return false;
 
+    // Currently we permit relative lookup table entries on 64-bit targets,
+    // and on 32-bit Arm. TODO: better comment explaining why just these
     Triple TargetTriple = TM.getTargetTriple();
-    if (!TargetTriple.isArch64Bit())
+    if (!TargetTriple.isArch64Bit() && TargetTriple.getArch() != Triple::arm)
       return false;
 
     // TODO: Triggers issues on aarch64 on darwin, so temporarily disable it
diff --git a/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
index ea628d7c3d7d6b..deb23e009b27f5 100644
--- a/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
+++ b/llvm/lib/Transforms/Utils/RelLookupTableConverter.cpp
@@ -18,10 +18,12 @@
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Module.h"
+#include "llvm/TargetParser/Triple.h"
 
 using namespace llvm;
 
-static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV) {
+static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV,
+                                          unsigned PointerSize) {
   // 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.
@@ -60,10 +62,12 @@ static bool shouldConvertToRelLookupTable(Module &M, GlobalVariable &GV) {
   if (!Array)
     return false;
 
-  // If values are not 64-bit pointers, do not generate a relative lookup table.
+  // If values are not pointers of the full width permitted by the
+  // architecture, do not generate a relative lookup table.
   const DataLayout &DL = M.getDataLayout();
   Type *ElemType = Array->getType()->getElementType();
-  if (!ElemType->isPointerTy() || DL.getPointerTypeSizeInBits(ElemType) != 64)
+  if (!ElemType->isPointerTy() ||
+      DL.getPointerTypeSizeInBits(ElemType) != PointerSize)
     return false;
 
   for (const Use &Op : Array->operands()) {
@@ -96,8 +100,8 @@ static GlobalVariable *createRelLookupTable(Function &Func,
   ConstantArray *LookupTableArr =
       cast<ConstantArray>(LookupTable.getInitializer());
   unsigned NumElts = LookupTableArr->getType()->getNumElements();
-  ArrayType *IntArrayTy =
-      ArrayType::get(Type::getInt32Ty(M.getContext()), NumElts);
+  Type *IntTy = Type::getInt32Ty(M.getContext());
+  ArrayType *IntArrayTy = ArrayType::get(IntTy, NumElts);
 
   GlobalVariable *RelLookupTable = new GlobalVariable(
     M, IntArrayTy, LookupTable.isConstant(), LookupTable.getLinkage(),
@@ -115,7 +119,9 @@ static GlobalVariable *createRelLookupTable(Function &Func,
     Constant *Target = llvm::ConstantExpr::getPtrToInt(Element, IntPtrTy);
     Constant *Sub = llvm::ConstantExpr::getSub(Target, Base);
     Constant *RelOffset =
-        llvm::ConstantExpr::getTrunc(Sub, Type::getInt32Ty(M.getContext()));
+        IntPtrTy->getScalarSizeInBits() > IntTy->getScalarSizeInBits()
+            ? llvm::ConstantExpr::getTrunc(Sub, IntTy)
+            : Sub;
     RelLookupTableContents[Idx++] = RelOffset;
   }
 
@@ -183,8 +189,13 @@ static bool convertToRelativeLookupTables(
 
   bool Changed = false;
 
+  auto Triple = llvm::Triple(M.getTargetTriple());
+  unsigned PointerSize = Triple.isArch64Bit()   ? 64
+                         : Triple.isArch32Bit() ? 32
+                                                : 16;
+
   for (GlobalVariable &GV : llvm::make_early_inc_range(M.globals())) {
-    if (!shouldConvertToRelLookupTable(M, GV))
+    if (!shouldConvertToRelLookupTable(M, GV, PointerSize))
       continue;
 
     convertToRelLookupTable(GV);
diff --git a/llvm/test/Transforms/RelLookupTableConverter/ARM/rel_lookup_table.ll b/llvm/test/Transforms/RelLookupTableConverter/ARM/rel_lookup_table.ll
new file mode 100644
index 00000000000000..e7df904fdc8e45
--- /dev/null
+++ b/llvm/test/Transforms/RelLookupTableConverter/ARM/rel_lookup_table.ll
@@ -0,0 +1,39 @@
+; RUN: opt -passes=rel-lookup-table-converter                       -mtriple=arm-none-eabi -S < %s | FileCheck %s --check-prefix=ABS
+; RUN: opt -passes=rel-lookup-table-converter -relocation-model=pic -mtriple=arm-none-eabi -S < %s | FileCheck %s --check-prefix=REL
+
+ at .str.0 = private unnamed_addr constant [6 x i8] c"Lorem\00", align 1
+ at .str.1 = private unnamed_addr constant [6 x i8] c"ipsum\00", align 1
+ at .str.2 = private unnamed_addr constant [6 x i8] c"dolor\00", align 1
+ at .str.3 = private unnamed_addr constant [4 x i8] c"sit\00", align 1
+ at .str.4 = private unnamed_addr constant [5 x i8] c"amet\00", align 1
+ at .str.5 = private unnamed_addr constant [12 x i8] c"consectetur\00", align 1
+ at .str.6 = private unnamed_addr constant [12 x i8] c"adipisicing\00", align 1
+ at .str.default = private unnamed_addr constant [5 x i8] c"elit\00", align 1
+ at .table = private unnamed_addr constant [7 x ptr] [
+  ptr @.str.0,
+  ptr @.str.1,
+  ptr @.str.2,
+  ptr @.str.3,
+  ptr @.str.4,
+  ptr @.str.5,
+  ptr @.str.6
+], align 4
+; ABS: @.table = private unnamed_addr constant [7 x ptr] [ptr @.str.0, ptr @.str.1, ptr @.str.2, ptr @.str.3, ptr @.str.4, ptr @.str.5, ptr @.str.6], align 4
+; REL: @reltable.lookup = private unnamed_addr constant [7 x i32] [i32 sub (i32 ptrtoint (ptr @.str.0 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.1 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.2 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.3 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.4 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.5 to i32), i32 ptrtoint (ptr @reltable.lookup to i32)), i32 sub (i32 ptrtoint (ptr @.str.6 to i32), i32 ptrtoint (ptr @reltable.lookup to i32))], align 4
+
+define noundef nonnull ptr @lookup(i32 noundef %s) {
+entry:
+  %0 = icmp ult i32 %s, 7
+  br i1 %0, label %table, label %return
+
+table:
+  %gep = getelementptr inbounds [7 x ptr], ptr @.table, i32 0, i32 %s
+  %element = load ptr, ptr %gep, align 4
+; ABS:    %element = load ptr, ptr %gep, align 4
+; REL:    {{%.*}} = call ptr @llvm.load.relative.i32(ptr @reltable.lookup, i32 {{%.*}})
+  br label %return
+
+return:                                           ; preds = %entry, %switch.lookup
+  %ret = phi ptr [ %element, %table ], [ @.str.default, %entry ]
+  ret ptr %ret
+}



More information about the llvm-commits mailing list