[llvm] [InstSimplify] Unwrap DSOLocalEquivalent in simplifyRelativeLoad (PR #225522)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 22 14:00:36 PDT 2026
https://github.com/PiJoules created https://github.com/llvm/llvm-project/pull/225522
When simplifying `@llvm.load.relative` against a relative table, the pointed to global can be a `DSOLocalEquivalent` (as used by relative vtables). Previously, this returned the `DSOLocalEquivalent` directly, leaking it into instruction operands (e.g. call operands).
Downstream passes like the inliner failed to inline the call because `CallBase::getCalledFunction()` returns `nullptr` for non-`Function` operands, and GlobalISel crashed attempting to translate the unhandled constant.
Unwrap `DSOLocalEquivalent` to its underlying `GlobalValue` so `@llvm.load.relative` simplifies to the target function directly.
>From 76440a3ca6d0e6d7984ad7f20c3217deafc39128 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan at google.com>
Date: Tue, 22 Sep 2026 20:21:52 +0000
Subject: [PATCH] [InstSimplify] Unwrap DSOLocalEquivalent in
simplifyRelativeLoad
When simplifying @llvm.load.relative against a constant relative table,
LoadedLHSPtr can be a DSOLocalEquivalent (as used by relative vtables).
Previously, this returned the DSOLocalEquivalent directly, leaking it
into instruction operands (e.g. call operands).
Downstream passes like the inliner failed to inline the call because
CallBase::getCalledFunction() returns nullptr for non-Function operands,
and GlobalISel crashed attempting to translate the unhandled constant.
Unwrap DSOLocalEquivalent to its underlying GlobalValue so
@llvm.load.relative simplifies to the target function directly.
---
llvm/lib/Analysis/InstructionSimplify.cpp | 2 ++
.../AArch64/GlobalISel/load-relative.ll | 15 +++++++++++++
llvm/test/Transforms/Inline/load-relative.ll | 21 +++++++++++++++++++
.../Transforms/InstSimplify/load-relative.ll | 11 ++++++++++
4 files changed, 49 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/load-relative.ll
create mode 100644 llvm/test/Transforms/Inline/load-relative.ll
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index baea0c2425812a..19a76d26c7c2c0 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -6563,6 +6563,8 @@ static Value *simplifyRelativeLoad(Constant *Ptr, Constant *Offset,
PtrSym != LoadedRHSSym || PtrOffset != LoadedRHSOffset)
return nullptr;
+ if (auto *Equiv = dyn_cast<DSOLocalEquivalent>(LoadedLHSPtr))
+ return Equiv->getGlobalValue();
return LoadedLHSPtr;
}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/load-relative.ll b/llvm/test/CodeGen/AArch64/GlobalISel/load-relative.ll
new file mode 100644
index 00000000000000..5a44d2da32b4ea
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/load-relative.ll
@@ -0,0 +1,15 @@
+; RUN: opt < %s -passes=instsimplify -S | llc -mtriple=aarch64 -global-isel -verify-machineinstrs -o - | FileCheck %s
+
+declare void @target()
+
+ at vt = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @target to i64), i64 ptrtoint (ptr @vt to i64)) to i32)]
+
+declare ptr @llvm.load.relative.i32(ptr, i32)
+
+; CHECK-LABEL: test:
+; CHECK: bl target
+define void @test() {
+ %fn = call ptr @llvm.load.relative.i32(ptr @vt, i32 0)
+ call void %fn()
+ ret void
+}
diff --git a/llvm/test/Transforms/Inline/load-relative.ll b/llvm/test/Transforms/Inline/load-relative.ll
new file mode 100644
index 00000000000000..9bb6397511e4e7
--- /dev/null
+++ b/llvm/test/Transforms/Inline/load-relative.ll
@@ -0,0 +1,21 @@
+; RUN: opt < %s -passes='module(function(instsimplify),cgscc(inline))' -S | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define internal i32 @callee() {
+ ret i32 42
+}
+
+ at vt = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @callee to i64), i64 ptrtoint (ptr @vt to i64)) to i32)]
+
+declare ptr @llvm.load.relative.i32(ptr, i32)
+
+; CHECK-LABEL: define i32 @caller
+; CHECK-NOT: call
+; CHECK: ret i32 42
+define i32 @caller() {
+ %fn = call ptr @llvm.load.relative.i32(ptr @vt, i32 0)
+ %res = call i32 %fn()
+ ret i32 %res
+}
diff --git a/llvm/test/Transforms/InstSimplify/load-relative.ll b/llvm/test/Transforms/InstSimplify/load-relative.ll
index 75d38d555d329b..6e9f4a84b27a6e 100644
--- a/llvm/test/Transforms/InstSimplify/load-relative.ll
+++ b/llvm/test/Transforms/InstSimplify/load-relative.ll
@@ -71,5 +71,16 @@ define ptr @f8() {
ret ptr %l
}
+ at c_equiv = constant i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @fn to i64), i64 ptrtoint (ptr @c_equiv to i64)) to i32)
+
+; CHECK-LABEL: @f_equiv
+; CHECK-NOT: dso_local_equivalent
+; CHECK: ret ptr @fn
+define ptr @f_equiv() {
+ %l = call ptr @llvm.load.relative.i32(ptr @c_equiv, i32 0)
+ ret ptr %l
+}
+
+declare void @fn()
declare ptr @llvm.load.relative.i32(ptr, i32)
declare ptr @llvm.load.relative.i64(ptr, i64)
More information about the llvm-commits
mailing list