[clang] [llvm] [ObjC][LTO] Propagate constant ivar offsets across ThinLTO and FullLTO (PR #205970)
Xiaoyang Gong via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 9 01:16:12 PDT 2026
https://github.com/KotoriAster updated https://github.com/llvm/llvm-project/pull/205970
>From d277c94ff36802657af9594a48f621854a3e8abb Mon Sep 17 00:00:00 2001
From: xiaoyanggong <xiaoyanggong at bytedance.com>
Date: Fri, 26 Jun 2026 10:04:25 +0800
Subject: [PATCH 1/2] [ObjC][LTO] Propagate constant ivar offsets across
ThinLTO and FullLTO
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
ObjC non-fragile ABI emits ivar offsets as mutable globals so the
runtime can slide them when a superclass changes layout. In practice,
when LTO can see the entire class hierarchy, those offsets are
statically known and the loads are redundant.
This pass resolves the inheritance chain at link time — via ThinLTO
module summaries or the merged FullLTO module — computes each ivar's
final offset, and marks the global constant. Downstream optimization
then folds the load into an immediate, eliminating one pointer-chase
per ivar access on hot paths.
Single-TU constification already exists in Clang's CodeGen; this
extends the same guarantee to cross-TU hierarchies that are only
complete at LTO.
Co-Authored-By: Claude <noreply at anthropic.com> (Claude-Opus-4.6)
Co-Authored-By: Zhaoxuan Jiang <jiangzhaoxuan94 at gmail.com>
---
clang/test/CodeGenObjC/lit.local.cfg | 5 +
clang/test/CodeGenObjC/objc-ivar-offset-e2e.m | 101 +++++
llvm/include/llvm/Bitcode/LLVMBitCodes.h | 3 +
llvm/include/llvm/IR/ModuleSummaryIndex.h | 22 +-
llvm/include/llvm/IR/ModuleSummaryIndexYAML.h | 39 ++
llvm/include/llvm/IR/ObjCClassHierarchy.h | 59 +++
.../Transforms/IPO/ObjCConstantIvarOffset.h | 36 ++
llvm/lib/Analysis/ModuleSummaryAnalysis.cpp | 4 +
llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp | 1 +
llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 16 +
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 22 ++
llvm/lib/IR/CMakeLists.txt | 1 +
llvm/lib/IR/ObjCClassHierarchy.cpp | 266 +++++++++++++
llvm/lib/LTO/LTO.cpp | 4 +
llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 4 +
llvm/lib/Passes/PassBuilder.cpp | 1 +
llvm/lib/Passes/PassBuilderPipelines.cpp | 5 +
llvm/lib/Passes/PassRegistry.def | 1 +
llvm/lib/Transforms/IPO/CMakeLists.txt | 1 +
.../Transforms/IPO/ObjCConstantIvarOffset.cpp | 121 ++++++
llvm/test/Bitcode/summary_version.ll | 2 +-
llvm/test/Other/new-pm-lto-defaults.ll | 1 +
.../ObjCConstantIvarOffset/alignment.ll | 201 ++++++++++
.../ObjCConstantIvarOffset/basic.ll | 169 ++++++++
.../ObjCConstantIvarOffset/custom-root.ll | 118 ++++++
.../incomplete-hierarchy.ll | 76 ++++
.../nsobject-external.ll | 193 +++++++++
.../ObjCConstantIvarOffset/pre-slide.ll | 371 ++++++++++++++++++
.../summary-serialization.ll | 71 ++++
.../thinlto-cross-module.ll | 141 +++++++
.../ObjCConstantIvarOffset/thinlto.ll | 218 ++++++++++
31 files changed, 2271 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGenObjC/objc-ivar-offset-e2e.m
create mode 100644 llvm/include/llvm/IR/ObjCClassHierarchy.h
create mode 100644 llvm/include/llvm/Transforms/IPO/ObjCConstantIvarOffset.h
create mode 100644 llvm/lib/IR/ObjCClassHierarchy.cpp
create mode 100644 llvm/lib/Transforms/IPO/ObjCConstantIvarOffset.cpp
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
create mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
diff --git a/clang/test/CodeGenObjC/lit.local.cfg b/clang/test/CodeGenObjC/lit.local.cfg
index 546691463d1ad..c77da64792046 100644
--- a/clang/test/CodeGenObjC/lit.local.cfg
+++ b/clang/test/CodeGenObjC/lit.local.cfg
@@ -1,2 +1,7 @@
+from lit.llvm import llvm_config
+
if any(target in config.target_triple for target in ("aix", "zos")):
config.unsupported = True
+
+if llvm_config.use_lld(required=False):
+ config.available_features.add("lld")
diff --git a/clang/test/CodeGenObjC/objc-ivar-offset-e2e.m b/clang/test/CodeGenObjC/objc-ivar-offset-e2e.m
new file mode 100644
index 0000000000000..287d481748392
--- /dev/null
+++ b/clang/test/CodeGenObjC/objc-ivar-offset-e2e.m
@@ -0,0 +1,101 @@
+// REQUIRES: x86-registered-target, system-darwin, lld
+//
+// End-to-end test:
+// - clang produces ObjC bitcode object files,
+// - ld64.lld links and runs ObjCConstantIvarOffsetPass under LTO,
+// - llvm-objdump confirms both the presliding and constant ivar offset folding
+//
+// NSObject(size 8)
+// `- Super(start 8, size 16: _x at 8, _hidden at 12)
+// `- Sub(local start 12, size 16 -> resolved start 16, size 20)
+//
+// RUN: rm -rf %t && split-file %s %t
+//
+// --- ThinLTO path ---
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto=thin -O1 -c %t/super.m -o %t/super.thin.o
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto=thin -O1 -c %t/sub.m -o %t/sub.thin.o
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto=thin -O1 -fuse-ld=lld -dynamiclib -Wl,-undefined,dynamic_lookup \
+// RUN: %t/super.thin.o %t/sub.thin.o -o %t/thin.dylib
+// RUN: llvm-objdump -d --x86-asm-syntax=intel %t/thin.dylib | FileCheck %s --check-prefix=ASM
+// RUN: llvm-objdump --syms --full-contents %t/thin.dylib | FileCheck %s --check-prefix=DATA
+//
+// --- FullLTO path ---
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto -O1 -c %t/super.m -o %t/super.full.o
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto -O1 -c %t/sub.m -o %t/sub.full.o
+// RUN: %clang -target x86_64-apple-macosx10.15.0 \
+// RUN: -flto -O1 -fuse-ld=lld -dynamiclib -Wl,-undefined,dynamic_lookup \
+// RUN: %t/super.full.o %t/sub.full.o -o %t/full.dylib
+// RUN: llvm-objdump -d --x86-asm-syntax=intel %t/full.dylib | FileCheck %s --check-prefix=ASM
+// RUN: llvm-objdump --syms --full-contents %t/full.dylib | FileCheck %s --check-prefix=DATA
+
+// Check that ivar accesses use folded immediate offsets.
+// Before: mov rax, qword ptr [rip + 0x...] ## 0x... <_OBJC_IVAR_$_Sub._y>
+// mov eax, dword ptr [r14 + rax]
+// After: mov eax, dword ptr [r14 + 0x10]
+//
+// Ivars are always [self + offset]; matching the addressing mode suffices.
+// ASM-LABEL: <-[Super bump:]>:
+// ASM-NOT: ptr{{.*}}## {{.*}}<_OBJC_IVAR_$_{{.*}}>
+// ASM: dword ptr [r{{[a-z0-9]+}} + 0x8]
+// ASM: dword ptr [r{{[a-z0-9]+}} + 0xc]
+//
+// ASM-LABEL: <-[Sub combined:]>:
+// ASM-NOT: ptr{{.*}}## {{.*}}<_OBJC_IVAR_$_{{.*}}>
+// ASM: dword ptr [r{{[a-z0-9]+}} + 0x10]
+
+// Check that ivar offset globals hold correctly preslid values.
+// DATA: SYMBOL TABLE:
+// DATA-DAG: [[#%x, SUPER_X:]] {{.*}} __DATA,__objc_ivar _OBJC_IVAR_$_Super._x
+// DATA-DAG: [[#%x, SUPER_H:]] {{.*}} __DATA,__objc_ivar _OBJC_IVAR_$_Super._hidden
+// DATA-DAG: [[#%x, SUB_Y:]] {{.*}} __DATA,__objc_ivar _OBJC_IVAR_$_Sub._y
+//
+// DATA: Contents of section __DATA,__objc_ivar:
+// _x=8, _hidden=12 on one row; _y=16 (preslid from 8).
+// DATA-NEXT: {{0*}}[[#SUPER_X]] 08000000 00000000 0c000000 00000000
+// DATA-NEXT: {{0*}}[[#SUB_Y]] 10000000 00000000
+
+//--- super.m
+#import <objc/NSObject.h>
+
+ at interface Super : NSObject
+ at property(nonatomic) int x;
+- (int)bump:(int)delta;
+ at end
+
+ at interface Super ()
+ at property(nonatomic) int hidden;
+ at end
+
+ at implementation Super
+- (int)bump:(int)delta {
+ _x += delta;
+ _hidden += delta > 0 ? delta : -delta;
+ return _x + _hidden;
+}
+ at end
+
+//--- sub.m
+#import <objc/NSObject.h>
+
+ at interface Super : NSObject
+ at property(nonatomic) int x;
+ at end
+
+ at interface Sub : Super
+ at property(nonatomic) int y;
+- (int)combined:(int)count;
+ at end
+
+ at implementation Sub
+- (int)combined:(int)count {
+ int total = self.x + _y;
+ for (int i = 0; i < count; ++i)
+ total += _y + i;
+ return total;
+}
+ at end
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 358f9a65a80af..327ba96a63af4 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -348,6 +348,9 @@ enum GlobalValueSummarySymtabCodes {
// nummib x alloc type,
// numver x version]
FS_COMBINED_ALLOC_INFO_NO_CONTEXT = 33,
+ // ObjC class hierarchy info for ivar offset constification.
+ // [classGUID, superclassGUID, instanceStart, instanceSize, maxIvarAlignment]
+ FS_OBJC_CLASS_INFO = 34,
};
enum MetadataCodes {
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h
index f4c5e9b40796b..9b3d6502e204e 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndex.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h
@@ -1513,6 +1513,15 @@ struct TypeIdOffsetVtableInfo {
/// to inheritance, which is why this is a vector.
using TypeIdCompatibleVtableInfo = std::vector<TypeIdOffsetVtableInfo>;
+/// ObjC class info for cross-module ivar offset constant constification.
+struct ObjCClassInfo {
+ GlobalValue::GUID SuperclassGUID; ///< Superclass GUID (0 = root class)
+ uint32_t InstanceStart; ///< From _class_ro_t field 1
+ uint32_t InstanceSize; ///< From _class_ro_t field 2
+ uint32_t MaxIvarAlignment; ///< Max alignment (1 << alignment_raw)
+ ///< across all ivars, or 1 if no ivars
+};
+
/// Class to hold module path string table and global value map,
/// and encapsulate methods for operating on them.
class ModuleSummaryIndex {
@@ -1621,6 +1630,9 @@ class ModuleSummaryIndex {
// built via releaseTemporaryMemory.
DenseMap<uint64_t, unsigned> StackIdToIndex;
+ /// Map from class GUID to its hierarchy/layout info.
+ DenseMap<GlobalValue::GUID, ObjCClassInfo> ObjCClasses;
+
// YAML I/O support.
friend yaml::MappingTraits<ModuleSummaryIndex>;
@@ -1643,7 +1655,7 @@ class ModuleSummaryIndex {
// in the way some record are interpreted, like flags for instance.
// Note that incrementing this may require changes in both BitcodeReader.cpp
// and BitcodeWriter.cpp.
- static constexpr uint64_t BitcodeSummaryVersion = 14;
+ static constexpr uint64_t BitcodeSummaryVersion = 15;
// Regular LTO module name for ASM writer
static constexpr const char *getRegularLTOModuleName() {
@@ -2064,6 +2076,14 @@ class ModuleSummaryIndex {
return I->second;
}
+ /// "ObjC class hierarchy info" accessors
+ const DenseMap<GlobalValue::GUID, ObjCClassInfo> &getObjCClasses() const {
+ return ObjCClasses;
+ }
+ DenseMap<GlobalValue::GUID, ObjCClassInfo> &getObjCClasses() {
+ return ObjCClasses;
+ }
+
/// Collect for the given module the list of functions it defines
/// (GUID -> Summary).
LLVM_ABI void
diff --git a/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h b/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
index 158c03e77306c..7f23713cd3bd3 100644
--- a/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
+++ b/llvm/include/llvm/IR/ModuleSummaryIndexYAML.h
@@ -316,6 +316,16 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
}
};
+template <> struct MappingTraits<ObjCClassInfo> {
+ static void mapping(IO &io, ObjCClassInfo &info) {
+ io.mapRequired("SuperclassGUID", info.SuperclassGUID);
+ io.mapRequired("InstanceStart", info.InstanceStart);
+ io.mapRequired("InstanceSize", info.InstanceSize);
+ io.mapOptional("MaxIvarAlignment", info.MaxIvarAlignment,
+ static_cast<uint32_t>(1));
+ }
+};
+
template <> struct CustomMappingTraits<TypeIdSummaryMapTy> {
static void inputOne(IO &io, StringRef Key, TypeIdSummaryMapTy &V) {
TypeIdSummary TId;
@@ -346,6 +356,22 @@ LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringAndGUID)
namespace llvm {
namespace yaml {
+template <> struct CustomMappingTraits<std::map<uint64_t, ObjCClassInfo>> {
+ static void inputOne(IO &io, StringRef Key,
+ std::map<uint64_t, ObjCClassInfo> &V) {
+ uint64_t KeyInt;
+ if (Key.getAsInteger(0, KeyInt)) {
+ io.setError("key not an integer");
+ return;
+ }
+ io.mapRequired(Key, V[KeyInt]);
+ }
+ static void output(IO &io, std::map<uint64_t, ObjCClassInfo> &V) {
+ for (auto &P : V)
+ io.mapRequired(llvm::utostr(P.first), P.second);
+ }
+};
+
template <> struct MappingTraits<ModuleSummaryIndex> {
static void mapping(IO &io, ModuleSummaryIndex& index) {
io.mapOptional("GlobalValueMap", index.GlobalValueMap);
@@ -370,6 +396,19 @@ template <> struct MappingTraits<ModuleSummaryIndex> {
io.mapOptional("WithGlobalValueDeadStripping",
index.WithGlobalValueDeadStripping);
+ if (io.outputting()) {
+ if (!index.ObjCClasses.empty()) {
+ std::map<uint64_t, ObjCClassInfo> SortedObjCClasses(
+ index.ObjCClasses.begin(), index.ObjCClasses.end());
+ io.mapOptional("ObjCClasses", SortedObjCClasses);
+ }
+ } else {
+ std::map<uint64_t, ObjCClassInfo> ObjCClasses;
+ io.mapOptional("ObjCClasses", ObjCClasses);
+ for (auto &[GUID, Info] : ObjCClasses)
+ index.ObjCClasses[GUID] = Info;
+ }
+
if (io.outputting()) {
auto CfiFunctionDefs = index.CfiFunctionDefs.getSortedSymbols();
io.mapOptional("CfiFunctionDefs", CfiFunctionDefs);
diff --git a/llvm/include/llvm/IR/ObjCClassHierarchy.h b/llvm/include/llvm/IR/ObjCClassHierarchy.h
new file mode 100644
index 0000000000000..43a7e8caf8ef7
--- /dev/null
+++ b/llvm/include/llvm/IR/ObjCClassHierarchy.h
@@ -0,0 +1,59 @@
+//===- ObjCClassHierarchy.h - ObjC class layout facts -----------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for collecting and resolving Objective-C class layout facts used by
+// ivar offset constification.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_IR_OBJCCLASSHIERARCHY_H
+#define LLVM_IR_OBJCCLASSHIERARCHY_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
+
+namespace llvm {
+
+class GlobalVariable;
+class Module;
+
+class ObjCClassHierarchy {
+public:
+ // A class whose ivar offsets and class_ro_t fields have been resolved.
+ struct ResolvedClass {
+ GlobalVariable *ROGV;
+ uint32_t InstanceStart;
+ uint32_t InstanceSize;
+ };
+
+ // Construct the resolved hierarchy from module IR. If ImportSummary is
+ // provided, use pre-resolved layout from the thin-link (ThinLTO path);
+ // otherwise resolve locally from the module alone (FullLTO path).
+ explicit ObjCClassHierarchy(const Module &M,
+ const ModuleSummaryIndex *ImportSummary);
+
+ // Emit per-module ObjC class summary records during module summary analysis.
+ static void exportToSummary(const Module &M, ModuleSummaryIndex &Index);
+ // Pre-slide the hierarchy graph materialized in this map; unreachable classes
+ // are erased.
+ static void
+ resolveHierarchy(DenseMap<GlobalValue::GUID, ObjCClassInfo> &Classes);
+
+ ArrayRef<ResolvedClass> getResolvedClasses() const { return Resolved; }
+ bool empty() const { return Resolved.empty(); }
+
+private:
+ SmallVector<ResolvedClass> Resolved;
+};
+
+} // end namespace llvm
+
+#endif // LLVM_IR_OBJCCLASSHIERARCHY_H
diff --git a/llvm/include/llvm/Transforms/IPO/ObjCConstantIvarOffset.h b/llvm/include/llvm/Transforms/IPO/ObjCConstantIvarOffset.h
new file mode 100644
index 0000000000000..f5514e9306a88
--- /dev/null
+++ b/llvm/include/llvm/Transforms/IPO/ObjCConstantIvarOffset.h
@@ -0,0 +1,36 @@
+//===- ObjCConstantIvarOffset.h - Constify ObjC ivar offsets ----*- 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
+//
+//===----------------------------------------------------------------------===//
+/// This pass promotes OBJC_IVAR_$_* offset globals to constants when the full
+/// class hierarchy is visible, pre-sliding offsets to match the runtime
+/// moveIvars().
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_IPO_OBJCCONSTANTIVAROFFSET_H
+#define LLVM_TRANSFORMS_IPO_OBJCCONSTANTIVAROFFSET_H
+
+#include "llvm/IR/PassManager.h"
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+
+class Module;
+class ModuleSummaryIndex;
+
+struct ObjCConstantIvarOffsetPass
+ : OptionalPassInfoMixin<ObjCConstantIvarOffsetPass> {
+ // Null for Full LTO
+ const ModuleSummaryIndex *ImportSummary;
+
+ ObjCConstantIvarOffsetPass(const ModuleSummaryIndex *IS)
+ : ImportSummary(IS) {}
+ LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
+};
+
+} // end namespace llvm
+
+#endif // LLVM_TRANSFORMS_IPO_OBJCCONSTANTIVAROFFSET_H
diff --git a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
index 0a2e5583c240b..6a18d273be08b 100644
--- a/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
+++ b/llvm/lib/Analysis/ModuleSummaryAnalysis.cpp
@@ -44,6 +44,7 @@
#include "llvm/IR/Metadata.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/IR/ObjCClassHierarchy.h"
#include "llvm/IR/Use.h"
#include "llvm/IR/User.h"
#include "llvm/InitializePasses.h"
@@ -1094,6 +1095,9 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
CantBePromoted, IsThinLTO, GetSSICallback);
}
+ // Compute ObjC class hierarchy info for ivar offset constification.
+ ObjCClassHierarchy::exportToSummary(M, Index);
+
// Compute summaries for all variables defined in module, and save in the
// index.
SmallVector<MDNode *, 2> Types;
diff --git a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
index 6574ab7a93c58..5687cd77931f3 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeAnalyzer.cpp
@@ -333,6 +333,7 @@ GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FS, ALLOC_CONTEXT_IDS)
STRINGIFY_CODE(FS, CONTEXT_RADIX_TREE_ARRAY)
STRINGIFY_CODE(FS, COMBINED_ALLOC_INFO_NO_CONTEXT)
+ STRINGIFY_CODE(FS, OBJC_CLASS_INFO)
}
case bitc::METADATA_ATTACHMENT_ID:
switch (CodeID) {
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index a5a11ab6221d4..0991b4bbd9961 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -8302,6 +8302,22 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
TheIndex.addBlockCount(Record[0]);
break;
+ case bitc::FS_OBJC_CLASS_INFO: {
+ // [classGUID, superclassGUID, instanceStart, instanceSize,
+ // maxIvarAlignment]
+ // Written by {Module,Index}BitcodeWriter::write*GlobalValueSummary().
+ if (Record.size() != 5)
+ return error("Invalid record");
+ GlobalValue::GUID ClassGUID = Record[0];
+ GlobalValue::GUID SuperGUID = Record[1];
+ uint32_t InstStart = static_cast<uint32_t>(Record[2]);
+ uint32_t InstSize = static_cast<uint32_t>(Record[3]);
+ uint32_t MaxAlign = static_cast<uint32_t>(Record[4]);
+ TheIndex.getObjCClasses()[ClassGUID] = {SuperGUID, InstStart, InstSize,
+ MaxAlign};
+ break;
+ }
+
case bitc::FS_PARAM_ACCESS: {
PendingParamAccesses = parseParamAccesses(Record);
break;
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index a6e7941a06699..e11de50757e0e 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -4999,6 +4999,17 @@ void ModuleBitcodeWriterBase::writePerModuleGlobalValueSummary() {
NameVals.clear();
}
+ // Write ObjC class hierarchy info.
+ for (const auto &[ClassGUID, Info] : Index->getObjCClasses()) {
+ NameVals.push_back(ClassGUID);
+ NameVals.push_back(Info.SuperclassGUID);
+ NameVals.push_back(Info.InstanceStart);
+ NameVals.push_back(Info.InstanceSize);
+ NameVals.push_back(Info.MaxIvarAlignment);
+ Stream.EmitRecord(bitc::FS_OBJC_CLASS_INFO, NameVals);
+ NameVals.clear();
+ }
+
if (Index->getBlockCount())
Stream.EmitRecord(bitc::FS_BLOCK_COUNT,
ArrayRef<uint64_t>{Index->getBlockCount()});
@@ -5420,6 +5431,17 @@ void IndexBitcodeWriter::writeCombinedGlobalValueSummary() {
}
}
+ // Write ObjC class hierarchy info.
+ for (const auto &[ClassGUID, Info] : Index.getObjCClasses()) {
+ NameVals.push_back(ClassGUID);
+ NameVals.push_back(Info.SuperclassGUID);
+ NameVals.push_back(Info.InstanceStart);
+ NameVals.push_back(Info.InstanceSize);
+ NameVals.push_back(Info.MaxIvarAlignment);
+ Stream.EmitRecord(bitc::FS_OBJC_CLASS_INFO, NameVals);
+ NameVals.clear();
+ }
+
if (Index.getBlockCount())
Stream.EmitRecord(bitc::FS_BLOCK_COUNT,
ArrayRef<uint64_t>{Index.getBlockCount()});
diff --git a/llvm/lib/IR/CMakeLists.txt b/llvm/lib/IR/CMakeLists.txt
index 3037f01083308..dd670532e9c4b 100644
--- a/llvm/lib/IR/CMakeLists.txt
+++ b/llvm/lib/IR/CMakeLists.txt
@@ -53,6 +53,7 @@ add_llvm_component_library(LLVMCore
Mangler.cpp
Metadata.cpp
Module.cpp
+ ObjCClassHierarchy.cpp
ModuleSummaryIndex.cpp
Operator.cpp
OptBisect.cpp
diff --git a/llvm/lib/IR/ObjCClassHierarchy.cpp b/llvm/lib/IR/ObjCClassHierarchy.cpp
new file mode 100644
index 0000000000000..91ef83c0cd332
--- /dev/null
+++ b/llvm/lib/IR/ObjCClassHierarchy.cpp
@@ -0,0 +1,266 @@
+//===- ObjCClassHierarchy.cpp - ObjC class layout facts -------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for collecting and resolving Objective-C class layout facts used by
+// ivar offset constification.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/ObjCClassHierarchy.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Casting.h"
+
+using namespace llvm;
+
+static constexpr uint32_t DarwinNonFragileNSObjectInstanceSize = 8;
+static constexpr StringLiteral NonFragileNSObjectClassName =
+ "OBJC_CLASS_$_NSObject";
+
+// IR parsing helpers.
+
+static std::optional<uint32_t> getStableRootSize(GlobalValue::GUID GUID) {
+ if (GUID ==
+ GlobalValue::getGUIDAssumingExternalLinkage(NonFragileNSObjectClassName))
+ return DarwinNonFragileNSObjectInstanceSize;
+ return std::nullopt;
+}
+
+static const GlobalVariable *stripToGlobal(const Constant *C) {
+ return C ? dyn_cast<GlobalVariable>(C->stripPointerCasts()) : nullptr;
+}
+
+template <typename ConstantT = ConstantStruct>
+static const ConstantT *getInitializerStruct(const GlobalVariable *GV) {
+ return (GV && GV->hasInitializer())
+ ? dyn_cast<ConstantT>(GV->getInitializer())
+ : nullptr;
+}
+
+// Walk over every ObjC class registered in the module's __objc_classlist and
+// __objc_nlclslist sections
+template <typename CallbackT>
+static void forEachClassListEntry(const Module &M, CallbackT &&Callback) {
+ for (const auto &GV : M.globals()) {
+ if (GV.isDeclaration())
+ continue;
+
+ StringRef Section = GV.getSection();
+ if (!Section.contains("__objc_classlist") &&
+ !Section.contains("__objc_nlclslist"))
+ continue;
+
+ const auto *ClassList = getInitializerStruct<ConstantArray>(&GV);
+ if (!ClassList)
+ continue;
+
+ for (const auto &Class : ClassList->operands()) {
+ const GlobalVariable *ClassGV =
+ stripToGlobal(cast<Constant>(Class.get()));
+ if (ClassGV)
+ Callback(*ClassGV);
+ }
+ }
+}
+
+namespace {
+
+// Intermediate raw class layout parsed from module IR, before pre-sliding.
+struct ParsedClassInfo {
+ ObjCClassInfo Layout = {0, 0, 0, 1};
+ GlobalVariable *ROGV = nullptr;
+};
+
+} // end anonymous namespace
+
+// Extract raw layout info from a _class_t global by walking the ObjC ABI v2
+// struct chain. Return nullopt if _class_t is malformed.
+static std::optional<ParsedClassInfo>
+parseClassInfo(const GlobalVariable *ClassGV) {
+ // _class_t: { isa, superclass, cache, vtable, ro_data }
+ auto ClassStruct = getInitializerStruct(ClassGV);
+ if (!ClassStruct || ClassStruct->getNumOperands() < 5)
+ return std::nullopt;
+
+ // _class_ro_t: { flags, instanceStart, instanceSize, ..., ivarList, ... }
+ GlobalVariable *ROGV =
+ const_cast<GlobalVariable *>(stripToGlobal(ClassStruct->getOperand(4)));
+ auto ROStruct = getInitializerStruct(ROGV);
+ if (!ROStruct || ROStruct->getNumOperands() < 8)
+ return std::nullopt;
+
+ const auto *Start = dyn_cast<ConstantInt>(ROStruct->getOperand(1));
+ const auto *Size = dyn_cast<ConstantInt>(ROStruct->getOperand(2));
+ if (!Start || !Size)
+ return std::nullopt;
+
+ // _ivar_t: { offset, name, type, alignment_raw, size }
+ ParsedClassInfo Info;
+ Info.ROGV = ROGV;
+ if (const GlobalVariable *SuperclassGV =
+ stripToGlobal(ClassStruct->getOperand(1)))
+ Info.Layout.SuperclassGUID = SuperclassGV->getGUID();
+ Info.Layout.InstanceStart = static_cast<uint32_t>(Start->getZExtValue());
+ Info.Layout.InstanceSize = static_cast<uint32_t>(Size->getZExtValue());
+
+ const GlobalVariable *IvarListGV = stripToGlobal(ROStruct->getOperand(7));
+ if (!IvarListGV || !IvarListGV->hasInitializer())
+ return Info;
+
+ const auto *IvarList = getInitializerStruct(IvarListGV);
+
+ // _ivar_list_t: { entsize, count, ivars }
+ if (!IvarList || IvarList->getNumOperands() < 3)
+ return Info;
+
+ const auto *Ivars = dyn_cast<ConstantArray>(IvarList->getOperand(2));
+ if (!Ivars)
+ return Info;
+
+ for (const auto &Ivar : Ivars->operands()) {
+ const auto *IvarStruct = dyn_cast<ConstantStruct>(Ivar.get());
+ if (!IvarStruct || IvarStruct->getNumOperands() < 5)
+ continue;
+
+ const auto *AlignRaw = dyn_cast<ConstantInt>(IvarStruct->getOperand(3));
+ if (!AlignRaw)
+ continue;
+ uint32_t Alignment = 1U << static_cast<uint32_t>(AlignRaw->getZExtValue());
+ if (Info.Layout.MaxIvarAlignment < Alignment)
+ Info.Layout.MaxIvarAlignment = Alignment;
+ }
+
+ return Info;
+}
+
+// Pre-slide the hierarchy graph materialized in this map; unreachable classes
+// are erased.
+void ObjCClassHierarchy::resolveHierarchy(
+ DenseMap<GlobalValue::GUID, ObjCClassInfo> &Classes) {
+ if (Classes.empty())
+ return;
+
+ // Hierarchy graph materialization.
+ DenseMap<GlobalValue::GUID, SmallVector<GlobalValue::GUID, 4>> Children;
+ for (const auto &[GUID, Info] : Classes)
+ if (Info.SuperclassGUID != 0)
+ Children[Info.SuperclassGUID].push_back(GUID);
+
+ // Mimic runtime moveIvars(): slide InstanceStart/Size by the aligned delta.
+ auto Slide = [](ObjCClassInfo &Info, uint32_t SuperSize) {
+ auto AlignIvarSlide = [](uint32_t Diff, uint32_t MaxIvarAlignment) {
+ if (Diff == 0 || MaxIvarAlignment <= 1)
+ return Diff;
+ uint32_t Mask = MaxIvarAlignment - 1;
+ return (Diff + Mask) & ~Mask;
+ };
+ uint32_t Diff =
+ AlignIvarSlide(SuperSize - Info.InstanceStart, Info.MaxIvarAlignment);
+ Info.InstanceStart += Diff;
+ Info.InstanceSize += Diff;
+ };
+
+ // Seed worklist with roots and direct subclasses of known stable roots.
+ DenseMap<GlobalValue::GUID, uint32_t> ResolvedSize;
+ SmallVector<GlobalValue::GUID> Worklist;
+ for (auto &[GUID, Info] : Classes) {
+ if (Info.SuperclassGUID == 0) {
+ ResolvedSize[GUID] = Info.InstanceSize;
+ Worklist.push_back(GUID);
+ continue;
+ }
+
+ std::optional<uint32_t> SuperSize = getStableRootSize(Info.SuperclassGUID);
+ if (!SuperSize || Classes.contains(Info.SuperclassGUID))
+ continue;
+
+ Slide(Info, *SuperSize);
+ ResolvedSize[GUID] = Info.InstanceSize;
+ Worklist.push_back(GUID);
+ }
+
+ // Top-down pre-sliding.
+ while (!Worklist.empty()) {
+ GlobalValue::GUID ParentGUID = Worklist.pop_back_val();
+ uint32_t ParentSize = ResolvedSize[ParentGUID];
+ for (auto ChildGUID : Children[ParentGUID]) {
+ if (!Classes.contains(ChildGUID) || ResolvedSize.contains(ChildGUID))
+ continue;
+ auto Child = Classes.find(ChildGUID);
+ Slide(Child->second, ParentSize);
+ ResolvedSize[ChildGUID] = Child->second.InstanceSize;
+ Worklist.push_back(ChildGUID);
+ }
+ }
+
+ // Erase classes that were never reached -- their hierarchy is incomplete.
+ SmallVector<GlobalValue::GUID, 8> UnresolvedClasses;
+ for (const auto &[GUID, Info] : Classes)
+ if (!ResolvedSize.contains(GUID))
+ UnresolvedClasses.push_back(GUID);
+ for (auto GUID : UnresolvedClasses)
+ Classes.erase(GUID);
+}
+
+// Build the list of classes eligible for constification.
+// ThinLTO: pair module IR handles with pre-resolved summary layout.
+// FullLTO: parse all classes locally, resolve hierarchy, then collect results.
+ObjCClassHierarchy::ObjCClassHierarchy(
+ const Module &M, const ModuleSummaryIndex *ImportSummary) {
+ // ThinLTO path: summary already contains resolved sizes from the thin link.
+ if (ImportSummary) {
+ const auto &Classes = ImportSummary->getObjCClasses();
+ forEachClassListEntry(M, [&](const GlobalVariable &ClassGV) {
+ auto SummaryIt = Classes.find(ClassGV.getGUID());
+ if (SummaryIt == Classes.end())
+ return;
+
+ // Only need the ROGV handle; layout comes from the summary.
+ if (std::optional<ParsedClassInfo> Info = parseClassInfo(&ClassGV)) {
+ Resolved.push_back({Info->ROGV, SummaryIt->second.InstanceStart,
+ SummaryIt->second.InstanceSize});
+ }
+ });
+ return;
+ }
+
+ // FullLTO path: collect all classes and their RO handles.
+ DenseMap<GlobalValue::GUID, ObjCClassInfo> Classes;
+ DenseMap<GlobalValue::GUID, GlobalVariable *> GUIDToROGV;
+
+ forEachClassListEntry(M, [&](const GlobalVariable &ClassGV) {
+ if (std::optional<ParsedClassInfo> Info = parseClassInfo(&ClassGV)) {
+ Classes[ClassGV.getGUID()] = Info->Layout;
+ GUIDToROGV[ClassGV.getGUID()] = Info->ROGV;
+ }
+ });
+
+ // Resolve hierarchy locally.
+ resolveHierarchy(Classes);
+
+ // Collect surviving classes into the final resolved list.
+ for (const auto &[GUID, ResolvedInfo] : Classes) {
+ auto It = GUIDToROGV.find(GUID);
+ if (It == GUIDToROGV.end())
+ continue;
+ Resolved.push_back(
+ {It->second, ResolvedInfo.InstanceStart, ResolvedInfo.InstanceSize});
+ }
+}
+
+// Export raw class layout facts into the summary index (producer side).
+void ObjCClassHierarchy::exportToSummary(const Module &M,
+ ModuleSummaryIndex &Index) {
+ forEachClassListEntry(M, [&](const GlobalVariable &ClassGV) {
+ std::optional<ParsedClassInfo> Info = parseClassInfo(&ClassGV);
+ if (!Info)
+ return;
+
+ Index.getObjCClasses()[ClassGV.getGUID()] = Info->Layout;
+ });
+}
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index b0fd1d77a2d66..53f6ae6c4b2ea 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -33,6 +33,7 @@
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Mangler.h"
#include "llvm/IR/Metadata.h"
+#include "llvm/IR/ObjCClassHierarchy.h"
#include "llvm/IR/RuntimeLibcalls.h"
#include "llvm/LTO/LTOBackend.h"
#include "llvm/Linker/IRMover.h"
@@ -2153,6 +2154,9 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
LocalWPDTargetsMap,
ExternallyVisibleSymbolNamesPtr);
+ // Resolve ObjC class hierarchy from the combined index.
+ ObjCClassHierarchy::resolveHierarchy(ThinLTO.CombinedIndex.getObjCClasses());
+
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
return ThinLTO.isPrevailingModuleForGUID(GUID, S->modulePath());
};
diff --git a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
index 2ad2f97bdf48b..64850daf5fc05 100644
--- a/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
+++ b/llvm/lib/LTO/ThinLTOCodeGenerator.cpp
@@ -30,6 +30,7 @@
#include "llvm/IR/LLVMRemarkStreamer.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/Mangler.h"
+#include "llvm/IR/ObjCClassHierarchy.h"
#include "llvm/IR/PassTimingInfo.h"
#include "llvm/IR/Verifier.h"
#include "llvm/IRReader/IRReader.h"
@@ -1079,6 +1080,9 @@ void ThinLTOCodeGenerator::run() {
runWholeProgramDevirtOnIndex(*Index, ExportedGUIDs, LocalWPDTargetsMap);
GUIDPreservedSymbols.insert_range(ExportedGUIDs);
+ // Resolve ObjC class hierarchy from the combined index.
+ ObjCClassHierarchy::resolveHierarchy(Index->getObjCClasses());
+
// Compute prevailing symbols
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
computePrevailingCopies(*Index, PrevailingCopy);
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 7f99f6376bcbf..113045281ac52 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -247,6 +247,7 @@
#include "llvm/Transforms/IPO/LowerTypeTests.h"
#include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
#include "llvm/Transforms/IPO/MergeFunctions.h"
+#include "llvm/Transforms/IPO/ObjCConstantIvarOffset.h"
#include "llvm/Transforms/IPO/OpenMPOpt.h"
#include "llvm/Transforms/IPO/PartialInlining.h"
#include "llvm/Transforms/IPO/SCCP.h"
diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp
index f89dc099a9128..a6f80b83f1e9c 100644
--- a/llvm/lib/Passes/PassBuilderPipelines.cpp
+++ b/llvm/lib/Passes/PassBuilderPipelines.cpp
@@ -70,6 +70,7 @@
#include "llvm/Transforms/IPO/MemProfContextDisambiguation.h"
#include "llvm/Transforms/IPO/MergeFunctions.h"
#include "llvm/Transforms/IPO/ModuleInliner.h"
+#include "llvm/Transforms/IPO/ObjCConstantIvarOffset.h"
#include "llvm/Transforms/IPO/OpenMPOpt.h"
#include "llvm/Transforms/IPO/PartialInlining.h"
#include "llvm/Transforms/IPO/SCCP.h"
@@ -1982,6 +1983,7 @@ ModulePassManager PassBuilder::buildThinLTODefaultPipeline(
// metadata and intrinsics.
MPM.addPass(WholeProgramDevirtPass(nullptr, ImportSummary));
MPM.addPass(LowerTypeTestsPass(nullptr, ImportSummary));
+ MPM.addPass(ObjCConstantIvarOffsetPass(ImportSummary));
}
if (Level == OptimizationLevel::O0) {
@@ -2083,6 +2085,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
// Try to run OpenMP optimizations, quick no-op if no OpenMP metadata present.
MPM.addPass(OpenMPOptPass(ThinOrFullLTOPhase::FullLTOPostLink));
+ // Promote ObjC ivar offset globals to constants with pre-sliding.
+ MPM.addPass(ObjCConstantIvarOffsetPass(/*ImportSummary=*/nullptr));
+
// Remove unused virtual tables to improve the quality of code generated by
// whole-program devirtualization and bitset lowering.
MPM.addPass(GlobalDCEPass(/*InLTOPostLink=*/true));
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 04fa421cebb4b..c38cc528859bf 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -128,6 +128,7 @@ MODULE_PASS("mir-strip-debug", StripDebugMachineModulePass())
MODULE_PASS("module-inline", ModuleInlinerPass())
MODULE_PASS("name-anon-globals", NameAnonGlobalPass())
MODULE_PASS("no-op-module", NoOpModulePass())
+MODULE_PASS("objc-constant-ivar-offset", ObjCConstantIvarOffsetPass(nullptr))
MODULE_PASS("norecurse-lto-inference", NoRecurseLTOInferencePass())
MODULE_PASS("nsan", NumericalStabilitySanitizerPass())
MODULE_PASS("openmp-opt", OpenMPOptPass())
diff --git a/llvm/lib/Transforms/IPO/CMakeLists.txt b/llvm/lib/Transforms/IPO/CMakeLists.txt
index a986b9485f563..2501e2bcc59d5 100644
--- a/llvm/lib/Transforms/IPO/CMakeLists.txt
+++ b/llvm/lib/Transforms/IPO/CMakeLists.txt
@@ -37,6 +37,7 @@ add_llvm_component_library(LLVMipo
MemProfContextDisambiguation.cpp
MergeFunctions.cpp
ModuleInliner.cpp
+ ObjCConstantIvarOffset.cpp
OpenMPOpt.cpp
PartialInlining.cpp
SampleContextTracker.cpp
diff --git a/llvm/lib/Transforms/IPO/ObjCConstantIvarOffset.cpp b/llvm/lib/Transforms/IPO/ObjCConstantIvarOffset.cpp
new file mode 100644
index 0000000000000..51f74be86dc0c
--- /dev/null
+++ b/llvm/lib/Transforms/IPO/ObjCConstantIvarOffset.cpp
@@ -0,0 +1,121 @@
+//===- ObjCConstantIvarOffset.cpp - Promote ObjC ivar offsets -------------===//
+//
+// 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 pass promotes OBJC_IVAR_$_* offset globals to constants when the full
+/// class hierarchy is visible, pre-sliding offsets to match the runtime
+/// moveIvars().
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/IPO/ObjCConstantIvarOffset.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Module.h"
+#include "llvm/IR/ModuleSummaryIndex.h"
+#include "llvm/IR/ObjCClassHierarchy.h"
+#include "llvm/IR/Type.h"
+
+using namespace llvm;
+
+// Collects ivar offset globals owned by this class's _class_ro_t,
+static SmallVector<GlobalVariable *, 4>
+collectIvarOffsetGlobals(GlobalVariable &ROGV) {
+ SmallVector<GlobalVariable *, 4> Offsets;
+ // Walk ROGV -> ivarList -> ivar[i] -> offset global.
+ // _class_ro_t: { flags, instanceStart, instanceSize, ..., ivarList, ... }
+ // _ivar_list_t: { entsize, count, ivars }
+ // _ivar_t: { offset, name, type, alignment_raw, size }
+
+ auto *ROStruct = dyn_cast<ConstantStruct>(ROGV.getInitializer());
+ if (!ROStruct || ROStruct->getNumOperands() < 8)
+ return Offsets;
+
+ auto *IvarListGV = dyn_cast_or_null<GlobalVariable>(
+ ROStruct->getOperand(7)->stripPointerCasts());
+ if (!IvarListGV || !IvarListGV->hasInitializer())
+ return Offsets;
+
+ auto *IvarList = dyn_cast<ConstantStruct>(IvarListGV->getInitializer());
+ if (!IvarList || IvarList->getNumOperands() < 3)
+ return Offsets;
+
+ auto *Ivars = dyn_cast<ConstantArray>(IvarList->getOperand(2));
+ if (!Ivars)
+ return Offsets;
+
+ for (const auto &Ivar : Ivars->operands()) {
+ auto *IvarStruct = dyn_cast<ConstantStruct>(Ivar.get());
+ if (!IvarStruct || IvarStruct->getNumOperands() < 5)
+ continue;
+ if (auto *OffsetGV = dyn_cast_or_null<GlobalVariable>(
+ IvarStruct->getOperand(0)->stripPointerCasts()))
+ Offsets.push_back(OffsetGV);
+ }
+
+ return Offsets;
+}
+
+// Apply resolved layout to one class: slide ivar offsets by the delta,
+// mark them constant, and update _class_ro_t instanceStart/Size.
+static bool
+applyResolvedLayout(const ObjCClassHierarchy::ResolvedClass &Class) {
+ GlobalVariable &ROGV = *Class.ROGV;
+ uint32_t InstanceStart = Class.InstanceStart;
+ uint32_t InstanceSize = Class.InstanceSize;
+
+ // Read the original instanceStart/Size from _class_ro_t.
+ auto *ROStruct = cast<ConstantStruct>(ROGV.getInitializer());
+ uint32_t OldStart =
+ cast<ConstantInt>(ROStruct->getOperand(1))->getZExtValue();
+ uint32_t OldSize = cast<ConstantInt>(ROStruct->getOperand(2))->getZExtValue();
+
+ uint32_t Diff = InstanceStart - OldStart;
+ bool Changed = false;
+
+ // Slide each OBJC_IVAR_$_* initializer and mark it constant.
+ auto IvarOffsets = collectIvarOffsetGlobals(ROGV);
+
+ for (auto *GV : IvarOffsets) {
+ if (Diff != 0 && GV->hasInitializer()) {
+ if (const auto *Old = dyn_cast<ConstantInt>(GV->getInitializer())) {
+ GV->setInitializer(
+ ConstantInt::get(Old->getType(), Old->getSExtValue() + Diff));
+ Changed = true;
+ }
+ }
+
+ if (!GV->isConstant()) {
+ GV->setConstant(true);
+ Changed = true;
+ }
+ }
+
+ // Update _class_ro_t if instanceStart or instanceSize changed.
+ if (OldStart != InstanceStart || OldSize != InstanceSize) {
+ SmallVector<Constant *, 10> Ops;
+ for (const auto &Op : ROStruct->operands())
+ Ops.push_back(cast<Constant>(Op.get()));
+ Type *I32Ty = Type::getInt32Ty(ROGV.getContext());
+ Ops[1] = ConstantInt::get(I32Ty, InstanceStart);
+ Ops[2] = ConstantInt::get(I32Ty, InstanceSize);
+ ROGV.setInitializer(ConstantStruct::get(ROStruct->getType(), Ops));
+ Changed = true;
+ }
+
+ return Changed;
+}
+
+PreservedAnalyses ObjCConstantIvarOffsetPass::run(Module &M,
+ ModuleAnalysisManager &MAM) {
+ ObjCClassHierarchy Hierarchy(M, ImportSummary);
+
+ bool Changed = false;
+ for (const auto &Class : Hierarchy.getResolvedClasses())
+ Changed |= applyResolvedLayout(Class);
+
+ return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
+}
diff --git a/llvm/test/Bitcode/summary_version.ll b/llvm/test/Bitcode/summary_version.ll
index fbc8bdbee0a16..235a1422e1fb0 100644
--- a/llvm/test/Bitcode/summary_version.ll
+++ b/llvm/test/Bitcode/summary_version.ll
@@ -2,7 +2,7 @@
; RUN: opt -module-summary %s -o - | llvm-bcanalyzer -dump | FileCheck %s
; CHECK: <GLOBALVAL_SUMMARY_BLOCK
-; CHECK: <VERSION op0=14/>
+; CHECK: <VERSION op0=15/>
diff --git a/llvm/test/Other/new-pm-lto-defaults.ll b/llvm/test/Other/new-pm-lto-defaults.ll
index 14f189194d0e3..d9007de9db630 100644
--- a/llvm/test/Other/new-pm-lto-defaults.ll
+++ b/llvm/test/Other/new-pm-lto-defaults.ll
@@ -33,6 +33,7 @@
; CHECK-EP: Running pass: NoOpModulePass
; CHECK-O: Running pass: CrossDSOCFIPass
; CHECK-O-NEXT: Running pass: OpenMPOptPass
+; CHECK-O-NEXT: Running pass: ObjCConstantIvarOffsetPass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass
; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy<{{.*}}Module
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
new file mode 100644
index 0000000000000..9034e3ff10795
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
@@ -0,0 +1,201 @@
+; Test that ivar offsets respect alignment when sliding across
+; a superclass with mixed-size fields (char + int padding).
+;
+; Hierarchy:
+; NSObject
+; `- Super
+; char c; // c at offset 8
+; int hidden1; // hidden1 at offset 9 (extension)
+; int hidden2; // hidden2 at offset 13 (extension)
+; `- Sub
+; double d; // d compiled at 16, slid to 24
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefix=SUB
+;
+; SUB: @"OBJC_IVAR_$_Sub.d" = {{.*}}constant i64 24
+; SUB: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 24, i32 32,
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/super.ll -o %t/super.bc
+; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
+; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.c,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden1,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden2,plx \
+; RUN: -r=%t/super.bc,__objc_empty_cache, \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Super, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Super, \
+; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_Sub.d,plx \
+; RUN: -r=%t/sub.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+
+; Segments:
+; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
+; super.ll / sub.ll - per-module IR, used by ThinLTO path
+
+;--- super.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { char c; } @end
+ at interface Super () {
+ int hidden1;
+ int hidden2;
+} @end
+ at implementation Super @end
+
+;--- sub.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { char c; } @end
+ at interface Sub : Super { double d; } @end
+ at implementation Sub @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
+llvm-link super.ll sub.ll -S -o -
+# body.ll is auto-generated by linking super.ll and sub.ll
+;--- body.ll
+; ModuleID = 'llvm-link'
+source_filename = "llvm-link"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._objc_cache = type opaque
+
+ at llvm.compiler.used = appending global [13 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$.5"], section "llvm.metadata"
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden1" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [8 x i8] c"hidden1\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden2" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [8 x i8] c"hidden2\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [3 x %struct._ivar_t] } { i32 32, i32 3, [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 0, i32 1 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden1", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden2", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_Sub.d" = global i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.3 = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.d", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 24, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$.5" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- super.ll
+; ModuleID = 'align_super.m'
+source_filename = "align_super.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden1" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [8 x i8] c"hidden1\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden2" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [8 x i8] c"hidden2\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [3 x %struct._ivar_t] } { i32 32, i32 3, [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 0, i32 1 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden1", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden2", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [8 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- sub.ll
+; ModuleID = 'align_sub.m'
+source_filename = "align_sub.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Super" = external global %struct._class_t
+@"OBJC_IVAR_$_Sub.d" = global i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.d", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 24, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
new file mode 100644
index 0000000000000..87a06d97b9fc2
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
@@ -0,0 +1,169 @@
+; Test that all ivars in a complete single-module hierarchy are
+; promoted to constant without sliding.
+;
+; Hierarchy:
+; NSObject
+; `- SuperClass
+; @property int x; // _x at offset 8
+; `- SubClass
+; @property int y; // _y at offset 12
+;
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
+;
+; SUPER: @"OBJC_IVAR_$_SuperClass._x" = {{.*}}constant i64 8
+; SUB: @"OBJC_IVAR_$_SubClass._y" = {{.*}}constant i64 12
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/body.ll -o %t/body.bc
+; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_SuperClass,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_SubClass,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_SuperClass,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_SubClass,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_SuperClass._x,plx \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_SubClass._y,plx \
+; RUN: -r=%t/body.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefixes=SUPER,SUB
+
+; Segments:
+; source.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - single module used by both FullLTO and ThinLTO paths
+
+;--- source.m
+#import <objc/NSObject.h>
+ at interface SuperClass : NSObject
+ at property int x;
+ at end
+ at interface SubClass : SuperClass
+ at property int y;
+ at end
+ at implementation SuperClass @end
+ at implementation SubClass @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
+# body.ll is auto-generated from source.m
+;--- body.ll
+; ModuleID = 'source.m'
+source_filename = "source.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._objc_method = type { ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._prop_t = type { ptr, ptr }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }] }, section "__DATA, __objc_const", align 8
+@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.6 = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.6, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+ at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.8 = private unnamed_addr constant [6 x i8] c"setY:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SubClass y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.8, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SubClass setY:]" }] }, section "__DATA, __objc_const", align 8
+@"OBJC_IVAR_$_SubClass._y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.9 = private unnamed_addr constant [3 x i8] c"_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._y", ptr @OBJC_METH_VAR_NAME_.9, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.11 = private unnamed_addr constant [7 x i8] c"Ti,V_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.10, ptr @OBJC_PROP_NAME_ATTR_.11 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.6, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_SuperClass", ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [22 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @OBJC_CLASS_NAME_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_NAME_.8, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.9, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_.10, ptr @OBJC_PROP_NAME_ATTR_.11, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) #0 {
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ store ptr %0, ptr %3, align 8
+ store ptr %1, ptr %4, align 8
+ %5 = load ptr, ptr %3, align 8
+ %6 = getelementptr inbounds i8, ptr %5, i64 8
+ %7 = load atomic i32, ptr %6 unordered, align 4
+ ret i32 %7
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ store ptr %0, ptr %4, align 8
+ store ptr %1, ptr %5, align 8
+ store i32 %2, ptr %6, align 4
+ %7 = load ptr, ptr %4, align 8
+ %8 = getelementptr inbounds i8, ptr %7, i64 8
+ %9 = load i32, ptr %6, align 4
+ store atomic i32 %9, ptr %8 unordered, align 4
+ ret void
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal i32 @"\01-[SubClass y]"(ptr noundef %0, ptr noundef %1) #0 {
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ store ptr %0, ptr %3, align 8
+ store ptr %1, ptr %4, align 8
+ %5 = load ptr, ptr %3, align 8
+ %6 = getelementptr inbounds i8, ptr %5, i64 12
+ %7 = load atomic i32, ptr %6 unordered, align 4
+ ret i32 %7
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal void @"\01-[SubClass setY:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ store ptr %0, ptr %4, align 8
+ store ptr %1, ptr %5, align 8
+ store i32 %2, ptr %6, align 4
+ %7 = load ptr, ptr %4, align 8
+ %8 = getelementptr inbounds i8, ptr %7, i64 12
+ %9 = load i32, ptr %6, align 4
+ store atomic i32 %9, ptr %8 unordered, align 4
+ ret void
+}
+
+attributes #0 = { noinline optnone ssp uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cmov,+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
new file mode 100644
index 0000000000000..d957a9ce63707
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
@@ -0,0 +1,118 @@
+; Test that two independent hierarchy trees (custom root + NSObject-based)
+; resolve without conflict.
+;
+; Hierarchy:
+; Root (no superclass)
+; int a; // a at offset 8
+; `- RootSub
+; int b; // b at offset 12
+;
+; NSObject (external, ABI-stable root)
+; `- ObjSub
+; int c; // c at offset 8
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=ROOT,ROOTSUB,OBJSUB
+;
+; ROOT: @"OBJC_IVAR_$_Root.a" = {{.*}}constant i64 8
+; ROOTSUB: @"OBJC_IVAR_$_RootSub.b" = {{.*}}constant i64 12
+; OBJSUB: @"OBJC_IVAR_$_ObjSub.c" = {{.*}}constant i64 8
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/body.ll -o %t/body.bc
+; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_Root,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_RootSub,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_ObjSub,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_Root,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_RootSub,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_ObjSub,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_Root.a,plx \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_RootSub.b,plx \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_ObjSub.c,plx \
+; RUN: -r=%t/body.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefixes=ROOT,ROOTSUB,OBJSUB
+
+; Segments:
+; source.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - single module used by both FullLTO and ThinLTO paths
+
+;--- source.m
+ at interface Root { int a; } @end
+ at interface RootSub : Root { int b; } @end
+ at implementation Root @end
+ at implementation RootSub @end
+
+#import <objc/NSObject.h>
+ at interface ObjSub : NSObject { int c; } @end
+ at implementation ObjSub @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
+# body.ll is auto-generated from source.m
+;--- body.ll
+; ModuleID = 'source.m'
+source_filename = "source.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+
+; --- Root tree (custom root, no superclass) ---
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Root\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Root" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_Root.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Root" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Root.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Root", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr null, ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Root" }, section "__DATA, __objc_data", align 8
+
+; --- RootSub (child of custom root) ---
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [8 x i8] c"RootSub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_RootSub" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_RootSub.b" = constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_RootSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_RootSub.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_RootSub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_RootSub", ptr @"OBJC_CLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_RootSub" }, section "__DATA, __objc_data", align 8
+
+; --- ObjSub (child of NSObject, the external ABI-stable root) ---
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_.3 = private unnamed_addr constant [7 x i8] c"ObjSub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.3, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_ObjSub" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_ObjSub.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_ObjSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_ObjSub.c", ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_.3, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_ObjSub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_ObjSub", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_ObjSub" }, section "__DATA, __objc_data", align 8
+
+; --- Class list and compiler.used ---
+@"OBJC_LABEL_CLASS_$" = private global [3 x ptr] [ptr @"OBJC_CLASS_$_Root", ptr @"OBJC_CLASS_$_RootSub", ptr @"OBJC_CLASS_$_ObjSub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [11 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Root", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @"_OBJC_$_INSTANCE_VARIABLES_RootSub", ptr @OBJC_CLASS_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_ObjSub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
new file mode 100644
index 0000000000000..3490c3143470a
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
@@ -0,0 +1,76 @@
+; Test that ivar offsets are NOT promoted when the superclass is
+; external and non-stable (incomplete hierarchy).
+;
+; Hierarchy:
+; UIViewController (external, no CLASS_RO visible)
+; `- MyController
+; int myIvar; // myIvar at offset 0 (unresolvable)
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefix=CONTROLLER
+;
+; CONTROLLER: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}global i64 0
+; CONTROLLER-NOT: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}constant
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/body.ll -o %t/body.bc
+; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_MyController,plx \
+; RUN: -r=%t/body.bc,_OBJC_CLASS_$_UIViewController, \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_MyController,plx \
+; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_UIViewController, \
+; RUN: -r=%t/body.bc,_OBJC_IVAR_$_MyController.myIvar,plx \
+; RUN: -r=%t/body.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=CONTROLLER
+
+; Segments:
+; source.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - single module used by both FullLTO and ThinLTO paths
+
+;--- source.m
+ at interface UIViewController @end
+ at interface MyController : UIViewController { int myIvar; } @end
+ at implementation MyController @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm source.m -o -
+# body.ll is auto-generated from source.m
+;--- body.ll
+; ModuleID = 'source.m'
+source_filename = "source.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_UIViewController" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [13 x i8] c"MyController\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_UIViewController", ptr @"OBJC_METACLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_MyController" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_UIViewController" = external global %struct._class_t
+@"OBJC_IVAR_$_MyController.myIvar" = global i64 0, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [7 x i8] c"myIvar\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_MyController" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_MyController.myIvar", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 0, i32 0, i32 4, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_MyController", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_MyController", ptr @"OBJC_CLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_MyController" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_MyController"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_MyController", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
+
+!0 = !{i32 1, !"Objective-C Version", i32 2}
+!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!3 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!5 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!6 = !{i32 8, !"PIC Level", i32 2}
+!7 = !{i32 7, !"uwtable", i32 2}
+!8 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
new file mode 100644
index 0000000000000..724ff82794cd2
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
@@ -0,0 +1,193 @@
+; Test that external NSObject is recognized as ABI-stable root
+; and cross-TU sliding works.
+;
+; Hierarchy:
+; NSObject (external, ABI-stable root)
+; `- Super
+; int x; // x at offset 8
+; int hidden; // hidden at offset 12 (extension)
+; `- Sub
+; int y; // y compiled at 12, slid to 16
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
+;
+; SUPER: @"OBJC_IVAR_$_Super.x" = {{.*}}constant i64 8
+; SUPER: @"OBJC_IVAR_$_Super.hidden" = {{.*}}constant i64 12
+; SUB: @"OBJC_IVAR_$_Sub.y" = {{.*}}constant i64 16
+; SUB: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20,
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/super.ll -o %t/super.bc
+; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
+; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.x,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden,plx \
+; RUN: -r=%t/super.bc,__objc_empty_cache, \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Super, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Super, \
+; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_Sub.y,plx \
+; RUN: -r=%t/sub.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=SUPER
+; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+
+; Segments:
+; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
+; super.ll / sub.ll - per-module IR, used by ThinLTO path
+
+;--- super.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { int x; } @end
+ at interface Super () { int hidden; } @end
+ at implementation Super @end
+
+;--- sub.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { int x; } @end
+ at interface Sub : Super { int y; } @end
+ at implementation Sub @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
+llvm-link super.ll sub.ll -S -o -
+# body.ll is auto-generated by linking super.ll and sub.ll
+;--- body.ll
+; ModuleID = 'llvm-link'
+source_filename = "llvm-link"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._objc_cache = type opaque
+
+ at llvm.compiler.used = appending global [11 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$.5"], section "llvm.metadata"
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.3 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$.5" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- super.ll
+; ModuleID = 'nsobject_super.m'
+source_filename = "nsobject_super.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- sub.ll
+; ModuleID = 'nsobject_sub.m'
+source_filename = "nsobject_sub.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Super" = external global %struct._class_t
+@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
new file mode 100644
index 0000000000000..6aa430c99db4c
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
@@ -0,0 +1,371 @@
+; Test that a subclass gets its instanceStart slid to account for
+; hidden extension ivars in the superclass.
+;
+; Hierarchy:
+; NSObject
+; `- SuperClass
+; @property int x; // _x at offset 8
+; @property int hidden_y; // _hidden_y at offset 12 (extension)
+; `- SubClass
+; @property int z; // _z compiled at 8, slid to 16
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
+;
+; SUPER: @"OBJC_IVAR_$_SuperClass._x" = {{.*}}constant i64 8
+; SUPER: @"OBJC_IVAR_$_SuperClass._hidden_y" = {{.*}}constant i64 12
+; SUB: @"OBJC_IVAR_$_SubClass._z" = {{.*}}constant i64 16
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/super.ll -o %t/super.bc
+; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
+; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_SuperClass,plx \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_SuperClass,plx \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_SuperClass._x,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_SuperClass._hidden_y,plx \
+; RUN: -r=%t/super.bc,__objc_empty_cache, \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_SubClass,plx \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_SuperClass, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_SubClass,plx \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_SuperClass, \
+; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_SubClass._z,plx \
+; RUN: -r=%t/sub.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=SUPER
+; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+
+; Segments:
+; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
+; super.ll / sub.ll - per-module IR, used by ThinLTO path
+
+;--- super.m
+#import <objc/NSObject.h>
+ at interface SuperClass : NSObject
+ at property int x;
+ at end
+ at interface SuperClass ()
+ at property int hidden_y;
+ at end
+ at implementation SuperClass @end
+
+;--- sub.m
+#import <objc/NSObject.h>
+ at interface SuperClass : NSObject
+ at property int x;
+ at end
+ at interface SubClass : SuperClass
+ at property int z;
+ at end
+ at implementation SubClass @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
+llvm-link super.ll sub.ll -S -o -
+# body.ll is auto-generated by linking super.ll and sub.ll
+;--- body.ll
+; ModuleID = 'llvm-link'
+source_filename = "llvm-link"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._objc_method = type { ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._prop_t = type { ptr, ptr }
+%struct._objc_cache = type opaque
+
+ at llvm.compiler.used = appending global [31 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8, ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.6, ptr @OBJC_METH_VAR_TYPE_.7, ptr @OBJC_METH_VAR_NAME_.1.8, ptr @OBJC_METH_VAR_TYPE_.2.9, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.3.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_.2, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$.11"], section "llvm.metadata"
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [13 x i8] c"setHidden_y:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [4 x %struct._objc_method] } { i32 24, i32 4, [4 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass hidden_y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setHidden_y:]" }] }, section "__DATA, __objc_const", align 8
+@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.5 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.6 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_SuperClass._hidden_y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [10 x i8] c"_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._hidden_y", ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.8 = private unnamed_addr constant [14 x i8] c"Ti,V_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.9 = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [2 x %struct._prop_t] } { i32 16, i32 2, [2 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8 }, %struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+@"OBJC_IVAR_$_SubClass._z" = hidden global i64 8, section "__DATA, __objc_ivar", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+ at OBJC_METH_VAR_NAME_.6 = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.7 = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.1.8 = private unnamed_addr constant [6 x i8] c"setZ:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2.9 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.6, ptr @OBJC_METH_VAR_TYPE_.7, ptr @"\01-[SubClass z]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1.8, ptr @OBJC_METH_VAR_TYPE_.2.9, ptr @"\01-[SubClass setZ:]" }] }, section "__DATA, __objc_const", align 8
+ at OBJC_METH_VAR_NAME_.3.3 = private unnamed_addr constant [3 x i8] c"_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._z", ptr @OBJC_METH_VAR_NAME_.3.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_.2 = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.2, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$.11" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) #0 {
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ store ptr %0, ptr %3, align 8
+ store ptr %1, ptr %4, align 8
+ %5 = load ptr, ptr %3, align 8
+ %6 = getelementptr inbounds i8, ptr %5, i64 8
+ %7 = load atomic i32, ptr %6 unordered, align 4
+ ret i32 %7
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ store ptr %0, ptr %4, align 8
+ store ptr %1, ptr %5, align 8
+ store i32 %2, ptr %6, align 4
+ %7 = load ptr, ptr %4, align 8
+ %8 = getelementptr inbounds i8, ptr %7, i64 8
+ %9 = load i32, ptr %6, align 4
+ store atomic i32 %9, ptr %8 unordered, align 4
+ ret void
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal i32 @"\01-[SuperClass hidden_y]"(ptr noundef %0, ptr noundef %1) #0 {
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ store ptr %0, ptr %3, align 8
+ store ptr %1, ptr %4, align 8
+ %5 = load ptr, ptr %3, align 8
+ %6 = getelementptr inbounds i8, ptr %5, i64 12
+ %7 = load atomic i32, ptr %6 unordered, align 4
+ ret i32 %7
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal void @"\01-[SuperClass setHidden_y:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ store ptr %0, ptr %4, align 8
+ store ptr %1, ptr %5, align 8
+ store i32 %2, ptr %6, align 4
+ %7 = load ptr, ptr %4, align 8
+ %8 = getelementptr inbounds i8, ptr %7, i64 12
+ %9 = load i32, ptr %6, align 4
+ store atomic i32 %9, ptr %8 unordered, align 4
+ ret void
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal i32 @"\01-[SubClass z]"(ptr noundef %0, ptr noundef %1) #0 {
+ %3 = alloca ptr, align 8
+ %4 = alloca ptr, align 8
+ store ptr %0, ptr %3, align 8
+ store ptr %1, ptr %4, align 8
+ %5 = load ptr, ptr %3, align 8
+ %6 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
+ %7 = getelementptr inbounds i8, ptr %5, i64 %6
+ %8 = load atomic i32, ptr %7 unordered, align 4
+ ret i32 %8
+}
+
+; Function Attrs: noinline optnone ssp uwtable
+define internal void @"\01-[SubClass setZ:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
+ %4 = alloca ptr, align 8
+ %5 = alloca ptr, align 8
+ %6 = alloca i32, align 4
+ store ptr %0, ptr %4, align 8
+ store ptr %1, ptr %5, align 8
+ store i32 %2, ptr %6, align 4
+ %7 = load ptr, ptr %4, align 8
+ %8 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
+ %9 = getelementptr inbounds i8, ptr %7, i64 %8
+ %10 = load i32, ptr %6, align 4
+ store atomic i32 %10, ptr %9 unordered, align 4
+ ret void
+}
+
+attributes #0 = { noinline optnone ssp uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cmov,+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+!10 = !{}
+;--- super.ll
+; ModuleID = 'preslide_super.m'
+source_filename = "preslide_super.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._objc_method = type { ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._prop_t = type { ptr, ptr }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [13 x i8] c"setHidden_y:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [4 x %struct._objc_method] } { i32 24, i32 4, [4 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass hidden_y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setHidden_y:]" }] }, section "__DATA, __objc_const", align 8
+@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.5 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.6 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_SuperClass._hidden_y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [10 x i8] c"_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._hidden_y", ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.8 = private unnamed_addr constant [14 x i8] c"Ti,V_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.9 = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [2 x %struct._prop_t] } { i32 16, i32 2, [2 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8 }, %struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [18 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8, ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) {
+ %3 = getelementptr inbounds i8, ptr %0, i64 8
+ %4 = load atomic i32, ptr %3 unordered, align 4
+ ret i32 %4
+}
+
+define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
+ %4 = getelementptr inbounds i8, ptr %0, i64 8
+ store atomic i32 %2, ptr %4 unordered, align 4
+ ret void
+}
+
+define internal i32 @"\01-[SuperClass hidden_y]"(ptr noundef %0, ptr noundef %1) {
+ %3 = getelementptr inbounds i8, ptr %0, i64 12
+ %4 = load atomic i32, ptr %3 unordered, align 4
+ ret i32 %4
+}
+
+define internal void @"\01-[SuperClass setHidden_y:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
+ %4 = getelementptr inbounds i8, ptr %0, i64 12
+ store atomic i32 %2, ptr %4 unordered, align 4
+ ret void
+}
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- sub.ll
+; ModuleID = 'preslide_sub.m'
+source_filename = "preslide_sub.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._objc_method = type { ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._prop_t = type { ptr, ptr }
+
+@"OBJC_IVAR_$_SubClass._z" = hidden global i64 8, section "__DATA, __objc_ivar", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_SuperClass" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_SuperClass" = external global %struct._class_t
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setZ:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SubClass z]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SubClass setZ:]" }] }, section "__DATA, __objc_const", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [3 x i8] c"_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._z", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+ at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [13 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+define internal i32 @"\01-[SubClass z]"(ptr noundef %0, ptr noundef %1) {
+ %3 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
+ %4 = getelementptr inbounds i8, ptr %0, i64 %3
+ %5 = load atomic i32, ptr %4 unordered, align 4
+ ret i32 %5
+}
+
+define internal void @"\01-[SubClass setZ:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
+ %4 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
+ %5 = getelementptr inbounds i8, ptr %0, i64 %4
+ store atomic i32 %2, ptr %5 unordered, align 4
+ ret void
+}
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+!10 = !{}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
new file mode 100644
index 0000000000000..94a9d9f895b9f
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
@@ -0,0 +1,71 @@
+; Test that ObjC class hierarchy info is correctly serialized into
+; per-module summary bitcode (FS_OBJC_CLASS_INFO records).
+;
+; Hierarchy:
+; NSObject
+; `- Super
+; int x; // x at offset 8
+; int hidden; // hidden at offset 12 (extension)
+;
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -module-summary %t/body.ll -o %t/out.bc
+; RUN: llvm-bcanalyzer --dump %t/out.bc | FileCheck %s
+;
+; Check that the class info record contains correct values:
+; op2=instanceStart(8), op3=instanceSize(16), op4=maxIvarAlignment(4)
+; CHECK: <OBJC_CLASS_INFO op0={{[0-9]+}} op1={{[0-9]+}} op2=8 op3=16 op4=4/>
+
+; Segments:
+; source.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - single module used by both FullLTO and ThinLTO paths
+
+;--- source.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { int x; } @end
+ at interface Super () { int hidden; } @end
+ at implementation Super @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
+# body.ll is auto-generated from source.m
+;--- body.ll
+; ModuleID = 'source.m'
+source_filename = "source.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
new file mode 100644
index 0000000000000..f418cbfbe68ad
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
@@ -0,0 +1,141 @@
+; Test cross-module ThinLTO sliding when Sub's compile-time instanceStart
+; is stale due to Super's hidden extension ivar.
+;
+; Hierarchy:
+; NSObject
+; `- Super
+; int x; // x at offset 8
+; int hidden; // hidden at offset 12 (extension)
+; `- Sub
+; int y; // y compiled at 12, slid to 16
+;
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
+; RUN: opt -module-summary %t/super.ll -o %t/super.bc
+; RUN: llvm-lto2 run %t/sub.bc %t/super.bc -save-temps -o %t/out \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Super, \
+; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_Sub.y,plx \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Sub,plx \
+; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Super, \
+; RUN: -r=%t/sub.bc,__objc_empty_cache, \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_CLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden,plx \
+; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.x,plx \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_Super,plx \
+; RUN: -r=%t/super.bc,__objc_empty_cache,
+;
+; Sub ivar offset should be slid from 12 to 16, and marked constant.
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+; Super ivars are already constant and should be unchanged.
+; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUPER
+;
+; SUB: @"OBJC_IVAR_$_Sub.y" = {{.*}}constant i64 16
+; SUPER: @"OBJC_IVAR_$_Super.x" = {{.*}}constant i64 8
+; SUPER: @"OBJC_IVAR_$_Super.hidden" = {{.*}}constant i64 12
+
+; Segments:
+; Super.m / Sub.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; super.ll / sub.ll - per-module IR, used by ThinLTO path
+
+;--- Super.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { int x; } @end
+ at interface Super () { int hidden; } @end
+ at implementation Super @end
+
+;--- Sub.m
+#import <objc/NSObject.h>
+ at interface Super : NSObject { int x; } @end
+ at interface Sub : Super { int y; } @end
+ at implementation Sub @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Super.m -o super.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Sub.m -o sub.ll
+cat super.ll
+echo ';--- sub.ll'
+cat sub.ll
+;--- super.ll
+; ModuleID = 'Super.m'
+source_filename = "Super.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- sub.ll
+; ModuleID = 'Sub.m'
+source_filename = "Sub.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Super" = external global %struct._class_t
+@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
new file mode 100644
index 0000000000000..7fb77ecd2ba4e
--- /dev/null
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
@@ -0,0 +1,218 @@
+; Test multi-level hierarchy with cascading slide across three levels
+; in a single merged module.
+;
+; Hierarchy:
+; NSObject
+; `- Base
+; int a; // a at offset 8
+; `- Middle
+; int b; // b at offset 12
+; int hidden; // hidden at offset 16 (extension)
+; `- Leaf
+; int c; // c compiled at 16, slid to 20
+;
+; --- FullLTO path ---
+; RUN: rm -rf %t && split-file %s %t
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=MIDDLE,LEAF
+;
+; MIDDLE: @"OBJC_IVAR_$_Base.a" = {{.*}}constant i64 8
+; MIDDLE: @"OBJC_IVAR_$_Middle.b" = {{.*}}constant i64 12
+; MIDDLE: @"OBJC_IVAR_$_Middle.hidden" = {{.*}}constant i64 16
+; LEAF: @"OBJC_IVAR_$_Leaf.c" = {{.*}}constant i64 20
+; LEAF: @"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 20, i32 24,
+;
+; --- ThinLTO path ---
+; RUN: opt -module-summary %t/middle.ll -o %t/middle.bc
+; RUN: opt -module-summary %t/leaf.ll -o %t/leaf.bc
+; RUN: llvm-lto2 run %t/middle.bc %t/leaf.bc -save-temps -o %t/out \
+; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_Base,plx \
+; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_Middle,plx \
+; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_NSObject, \
+; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_Base,plx \
+; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_Middle,plx \
+; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Base.a,plx \
+; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Middle.b,plx \
+; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Middle.hidden,plx \
+; RUN: -r=%t/middle.bc,__objc_empty_cache, \
+; RUN: -r=%t/leaf.bc,_OBJC_CLASS_$_Leaf,plx \
+; RUN: -r=%t/leaf.bc,_OBJC_CLASS_$_Middle, \
+; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_Leaf,plx \
+; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_NSObject, \
+; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_Middle, \
+; RUN: -r=%t/leaf.bc,_OBJC_IVAR_$_Leaf.c,plx \
+; RUN: -r=%t/leaf.bc,__objc_empty_cache,
+; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=MIDDLE
+; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=LEAF
+
+; Segments:
+; middle.m / leaf.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; body.ll - merged module (llvm-link of middle+leaf), used by FullLTO path
+; middle.ll / leaf.ll - per-module IR, used by ThinLTO path
+
+;--- middle.m
+#import <objc/NSObject.h>
+ at interface Base : NSObject { int a; } @end
+ at interface Middle : Base { int b; } @end
+ at interface Middle () { int hidden; } @end
+ at implementation Base @end
+ at implementation Middle @end
+
+;--- leaf.m
+#import <objc/NSObject.h>
+ at interface Base : NSObject { int a; } @end
+ at interface Middle : Base { int b; } @end
+ at interface Leaf : Middle { int c; } @end
+ at implementation Leaf @end
+
+;--- gen
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) middle.m -o middle.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) leaf.m -o leaf.ll
+llvm-link middle.ll leaf.ll -S -o -
+# body.ll is auto-generated by linking middle.ll and leaf.ll
+;--- body.ll
+; ModuleID = 'llvm-link'
+source_filename = "llvm-link"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+%struct._objc_cache = type opaque
+
+ at llvm.compiler.used = appending global [14 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.2, ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.5, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr @"OBJC_LABEL_CLASS_$.7"], section "llvm.metadata"
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Base\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Base.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Base" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Base.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Base", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [7 x i8] c"Middle\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_IVAR_$_Middle.b" = constant i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"OBJC_IVAR_$_Middle.hidden" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Middle" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.hidden", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 0, i32 12, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_Base", ptr @"OBJC_CLASS_$_Middle"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.2 = private unnamed_addr constant [5 x i8] c"Leaf\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.2, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Middle", ptr @"OBJC_CLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_Leaf.c" = global i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_.5 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Leaf" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Leaf.c", ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.5, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.2, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Leaf", ptr @"OBJC_CLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$.7" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Leaf"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- middle.ll
+; ModuleID = 'thinlto_middle.m'
+source_filename = "thinlto_middle.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Base\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_IVAR_$_Base.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Base" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Base.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Base", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
+ at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [7 x i8] c"Middle\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
+@"OBJC_IVAR_$_Middle.b" = global i64 12, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"OBJC_IVAR_$_Middle.hidden" = hidden global i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Middle" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.hidden", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 0, i32 12, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Middle", ptr @"OBJC_CLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_Base", ptr @"OBJC_CLASS_$_Middle"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [9 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
+;--- leaf.ll
+; ModuleID = 'thinlto_leaf.m'
+source_filename = "thinlto_leaf.m"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.15.0"
+
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
+
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_Middle" = external global %struct._class_t
+ at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Leaf\00", section "__TEXT,__objc_classname,cstring_literals", align 1
+@"_OBJC_METACLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_METACLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
+@"OBJC_CLASS_$_Middle" = external global %struct._class_t
+@"OBJC_IVAR_$_Leaf.c" = global i64 16, section "__DATA, __objc_ivar", align 8
+ at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
+ at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
+@"_OBJC_$_INSTANCE_VARIABLES_Leaf" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Leaf.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
+@"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr null, ptr null }, section "__DATA, __objc_const", align 8
+@"OBJC_CLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Leaf", ptr @"OBJC_CLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
+@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Leaf"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
+ at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+
+!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+
+!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
+!1 = !{i32 1, !"Objective-C Version", i32 2}
+!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
+!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
+!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
+!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
+!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
+!7 = !{i32 8, !"PIC Level", i32 2}
+!8 = !{i32 7, !"uwtable", i32 2}
+!9 = !{i32 7, !"frame-pointer", i32 2}
>From 1aa38266635029b30dbde9e530f6f13d0123b067 Mon Sep 17 00:00:00 2001
From: xiaoyanggong <xiaoyanggong at bytedance.com>
Date: Thu, 9 Jul 2026 15:44:28 +0800
Subject: [PATCH 2/2] minimize the regression tests by reducing unused
annotation and function body
---
.../ObjCConstantIvarOffset/alignment.ll | 197 +++-------
.../ObjCConstantIvarOffset/basic.ll | 201 +++-------
.../ObjCConstantIvarOffset/custom-root.ll | 144 ++++---
.../incomplete-hierarchy.ll | 77 ++--
.../nsobject-external.ll | 186 ++-------
.../ObjCConstantIvarOffset/pre-slide.ll | 372 +++---------------
.../summary-serialization.ll | 59 +--
.../thinlto-cross-module.ll | 97 ++---
.../ObjCConstantIvarOffset/thinlto.ll | 218 ----------
9 files changed, 330 insertions(+), 1221 deletions(-)
delete mode 100644 llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
index 9034e3ff10795..9fda717399168 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/alignment.ll
@@ -1,56 +1,30 @@
-; Test that ivar offsets respect alignment when sliding across
-; a superclass with mixed-size fields (char + int padding).
+; Test that ivar sliding uses the subclass's max ivar alignment.
;
; Hierarchy:
; NSObject
; `- Super
-; char c; // c at offset 8
-; int hidden1; // hidden1 at offset 9 (extension)
-; int hidden2; // hidden2 at offset 13 (extension)
+; char c; // c at offset 8
+; int hidden1; // hidden1 at offset 12
+; int hidden2; // hidden2 at offset 16
; `- Sub
-; double d; // d compiled at 16, slid to 24
+; double d; // d compiled at 16, slid to 24
;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefix=SUB
-;
-; SUB: @"OBJC_IVAR_$_Sub.d" = {{.*}}constant i64 24
-; SUB: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 24, i32 32,
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/super.ll -o %t/super.bc
-; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
-; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_Super,plx \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_Super,plx \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.c,plx \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden1,plx \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden2,plx \
-; RUN: -r=%t/super.bc,__objc_empty_cache, \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Sub,plx \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Super, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Sub,plx \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Super, \
-; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_Sub.d,plx \
-; RUN: -r=%t/sub.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+; RUN: llvm-link %t/super.ll %t/sub.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
+
+; CHECK: @"OBJC_IVAR_$_Sub.d" = {{.*}}constant i64 24
+; CHECK: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 24, i32 32,
; Segments:
; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
; gen - refresher
-; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
-; super.ll / sub.ll - per-module IR, used by ThinLTO path
+; super.ll / sub.ll - hand-reduced cross-module IR
;--- super.m
#import <objc/NSObject.h>
@interface Super : NSObject { char c; } @end
- at interface Super () {
- int hidden1;
- int hidden2;
-} @end
+ at interface Super () { int hidden1; int hidden2; } @end
@implementation Super @end
;--- sub.m
@@ -62,65 +36,9 @@
;--- gen
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
-llvm-link super.ll sub.ll -S -o -
-# body.ll is auto-generated by linking super.ll and sub.ll
-;--- body.ll
-; ModuleID = 'llvm-link'
-source_filename = "llvm-link"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._objc_cache = type opaque
- at llvm.compiler.used = appending global [13 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$.5"], section "llvm.metadata"
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden1" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [8 x i8] c"hidden1\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden2" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [8 x i8] c"hidden2\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [3 x %struct._ivar_t] } { i32 32, i32 3, [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 0, i32 1 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden1", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden2", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_Sub.d" = global i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.3 = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.d", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 24, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$.5" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
;--- super.ll
-; ModuleID = 'align_super.m'
-source_filename = "align_super.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "super.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -129,41 +47,27 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden1" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [8 x i8] c"hidden1\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden2" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [8 x i8] c"hidden2\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [3 x %struct._ivar_t] } { i32 32, i32 3, [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 0, i32 1 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden1", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden2", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.2, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [8 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [6 x i8] c"Super\00"
+ at IvarC = private unnamed_addr constant [2 x i8] c"c\00"
+ at IvarHidden1 = private unnamed_addr constant [8 x i8] c"hidden1\00"
+ at IvarHidden2 = private unnamed_addr constant [8 x i8] c"hidden2\00"
+ at CharTy = private unnamed_addr constant [2 x i8] c"c\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Super.c" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_Super.hidden1" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_Super.hidden2" = global i64 16, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Super" = internal global { i32, i32, [3 x %struct._ivar_t] } { i32 32, i32 3, [3 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.c", ptr @IvarC, ptr @CharTy, i32 0, i32 1 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden1", ptr @IvarHidden1, ptr @IntTy, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden2", ptr @IvarHidden2, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 20, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Super", ptr null, ptr null }
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
;--- sub.ll
-; ModuleID = 'align_sub.m'
-source_filename = "align_sub.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "sub.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -172,30 +76,17 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Super" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_Super" = external global %struct._class_t
-@"OBJC_IVAR_$_Sub.d" = global i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"d\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.d", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 3, i32 8 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 24, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SubName = private unnamed_addr constant [4 x i8] c"Sub\00"
+ at IvarD = private unnamed_addr constant [2 x i8] c"d\00"
+ at DoubleTy = private unnamed_addr constant [2 x i8] c"d\00"
+@"OBJC_IVAR_$_Sub.d" = global i64 16, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.d", ptr @IvarD, ptr @DoubleTy, i32 3, i32 8 }] }
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 24, ptr null, ptr @SubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Sub", ptr null, ptr null }
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }
+ at SubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
index 87a06d97b9fc2..5c49b017e2931 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/basic.ll
@@ -1,169 +1,86 @@
-; Test that all ivars in a complete single-module hierarchy are
-; promoted to constant without sliding.
+; Test that a hierarchy split across modules is constified by the FullLTO
+; post-link pipeline. The frontend cannot constify SubClass while SuperClass is
+; only a declaration in the SubClass translation unit.
;
; Hierarchy:
; NSObject
; `- SuperClass
-; @property int x; // _x at offset 8
+; int x; // x at offset 8
; `- SubClass
-; @property int y; // _y at offset 12
+; int y; // y at offset 12
;
-;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
-;
-; SUPER: @"OBJC_IVAR_$_SuperClass._x" = {{.*}}constant i64 8
-; SUB: @"OBJC_IVAR_$_SubClass._y" = {{.*}}constant i64 12
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/body.ll -o %t/body.bc
-; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_SuperClass,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_SubClass,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_SuperClass,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_SubClass,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_SuperClass._x,plx \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_SubClass._y,plx \
-; RUN: -r=%t/body.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefixes=SUPER,SUB
+; RUN: llvm-link %t/super.ll %t/sub.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
+
+; CHECK: @"OBJC_IVAR_$_SuperClass.x" = {{.*}}constant i64 8
+; CHECK: @"OBJC_IVAR_$_SubClass.y" = {{.*}}constant i64 12
; Segments:
-; source.m - ingredients (requires Darwin SDK to regenerate)
-; gen - refresher
-; body.ll - single module used by both FullLTO and ThinLTO paths
+; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
+; gen - refresher
+; super.ll / sub.ll - hand-reduced cross-module IR
-;--- source.m
+;--- super.m
#import <objc/NSObject.h>
- at interface SuperClass : NSObject
- at property int x;
- at end
- at interface SubClass : SuperClass
- at property int y;
- at end
+ at interface SuperClass : NSObject { int x; } @end
@implementation SuperClass @end
+
+;--- sub.m
+#import <objc/NSObject.h>
+ at interface SuperClass : NSObject @end
+ at interface SubClass : SuperClass { int y; } @end
@implementation SubClass @end
;--- gen
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
-# body.ll is auto-generated from source.m
-;--- body.ll
-; ModuleID = 'source.m'
-source_filename = "source.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
+clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
+
+;--- super.ll
+source_filename = "super.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._objc_method = type { ptr, ptr, ptr }
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._prop_t = type { ptr, ptr }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }] }, section "__DATA, __objc_const", align 8
-@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.6 = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.6, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
- at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.8 = private unnamed_addr constant [6 x i8] c"setY:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SubClass y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.8, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SubClass setY:]" }] }, section "__DATA, __objc_const", align 8
-@"OBJC_IVAR_$_SubClass._y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.9 = private unnamed_addr constant [3 x i8] c"_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._y", ptr @OBJC_METH_VAR_NAME_.9, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.11 = private unnamed_addr constant [7 x i8] c"Ti,V_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.10, ptr @OBJC_PROP_NAME_ATTR_.11 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.6, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_SuperClass", ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [22 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @OBJC_CLASS_NAME_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_NAME_.8, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.9, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_.10, ptr @OBJC_PROP_NAME_ATTR_.11, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) #0 {
- %3 = alloca ptr, align 8
- %4 = alloca ptr, align 8
- store ptr %0, ptr %3, align 8
- store ptr %1, ptr %4, align 8
- %5 = load ptr, ptr %3, align 8
- %6 = getelementptr inbounds i8, ptr %5, i64 8
- %7 = load atomic i32, ptr %6 unordered, align 4
- ret i32 %7
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
- %4 = alloca ptr, align 8
- %5 = alloca ptr, align 8
- %6 = alloca i32, align 4
- store ptr %0, ptr %4, align 8
- store ptr %1, ptr %5, align 8
- store i32 %2, ptr %6, align 4
- %7 = load ptr, ptr %4, align 8
- %8 = getelementptr inbounds i8, ptr %7, i64 8
- %9 = load i32, ptr %6, align 4
- store atomic i32 %9, ptr %8 unordered, align 4
- ret void
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal i32 @"\01-[SubClass y]"(ptr noundef %0, ptr noundef %1) #0 {
- %3 = alloca ptr, align 8
- %4 = alloca ptr, align 8
- store ptr %0, ptr %3, align 8
- store ptr %1, ptr %4, align 8
- %5 = load ptr, ptr %3, align 8
- %6 = getelementptr inbounds i8, ptr %5, i64 12
- %7 = load atomic i32, ptr %6 unordered, align 4
- ret i32 %7
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal void @"\01-[SubClass setY:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
- %4 = alloca ptr, align 8
- %5 = alloca ptr, align 8
- %6 = alloca i32, align 4
- store ptr %0, ptr %4, align 8
- store ptr %1, ptr %5, align 8
- store i32 %2, ptr %6, align 4
- %7 = load ptr, ptr %4, align 8
- %8 = getelementptr inbounds i8, ptr %7, i64 12
- %9 = load i32, ptr %6, align 4
- store atomic i32 %9, ptr %8 unordered, align 4
- ret void
-}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [11 x i8] c"SuperClass\00"
+ at IvarX = private unnamed_addr constant [2 x i8] c"x\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_SuperClass.x" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_SuperClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass.x", ptr @IvarX, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_SuperClass", ptr null, ptr null }
+@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }
+@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
-attributes #0 = { noinline optnone ssp uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cmov,+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
+;--- sub.ll
+source_filename = "sub.m"
+target triple = "x86_64-apple-macosx10.15.0"
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_CLASS_$_SuperClass" = external global %struct._class_t
+@"OBJC_METACLASS_$_SuperClass" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SubName = private unnamed_addr constant [9 x i8] c"SubClass\00"
+ at IvarY = private unnamed_addr constant [2 x i8] c"y\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_SubClass.y" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass.y", ptr @IvarY, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @SubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_SubClass", ptr null, ptr null }
+@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }
+@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }
+ at SubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
index d957a9ce63707..caf968c2813e7 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/custom-root.ll
@@ -1,45 +1,28 @@
; Test that two independent hierarchy trees (custom root + NSObject-based)
-; resolve without conflict.
+; resolve without conflict when the implementations are split across modules.
;
; Hierarchy:
; Root (no superclass)
-; int a; // a at offset 8
+; int a; // a at offset 8
; `- RootSub
-; int b; // b at offset 12
+; int b; // b at offset 12
;
; NSObject (external, ABI-stable root)
; `- ObjSub
-; int c; // c at offset 8
+; int c; // c at offset 8
;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=ROOT,ROOTSUB,OBJSUB
-;
-; ROOT: @"OBJC_IVAR_$_Root.a" = {{.*}}constant i64 8
-; ROOTSUB: @"OBJC_IVAR_$_RootSub.b" = {{.*}}constant i64 12
-; OBJSUB: @"OBJC_IVAR_$_ObjSub.c" = {{.*}}constant i64 8
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/body.ll -o %t/body.bc
-; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_Root,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_RootSub,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_ObjSub,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_Root,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_RootSub,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_ObjSub,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_Root.a,plx \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_RootSub.b,plx \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_ObjSub.c,plx \
-; RUN: -r=%t/body.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefixes=ROOT,ROOTSUB,OBJSUB
+; RUN: llvm-link %t/root.ll %t/root-sub.ll %t/obj-sub.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
+
+; CHECK: @"OBJC_IVAR_$_Root.a" = {{.*}}constant i64 8
+; CHECK: @"OBJC_IVAR_$_RootSub.b" = {{.*}}constant i64 12
+; CHECK: @"OBJC_IVAR_$_ObjSub.c" = {{.*}}constant i64 8
; Segments:
; source.m - ingredients (requires Darwin SDK to regenerate)
; gen - refresher
-; body.ll - single module used by both FullLTO and ThinLTO paths
+; *.ll - hand-reduced cross-module IR
;--- source.m
@interface Root { int a; } @end
@@ -53,11 +36,9 @@
;--- gen
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
-# body.ll is auto-generated from source.m
-;--- body.ll
-; ModuleID = 'source.m'
-source_filename = "source.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
+;--- root.ll
+source_filename = "root.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -66,53 +47,62 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
+ at RootName = private unnamed_addr constant [5 x i8] c"Root\00"
+ at IvarA = private unnamed_addr constant [2 x i8] c"a\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Root.a" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Root" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Root.a", ptr @IvarA, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @RootName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @RootName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Root", ptr null, ptr null }
+@"OBJC_METACLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Root" }
+@"OBJC_CLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr null, ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Root" }
+ at RootClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Root"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @RootClassList], section "llvm.metadata"
-; --- Root tree (custom root, no superclass) ---
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Root\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Root" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_Root.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Root" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Root.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Root" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Root", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Root" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr null, ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Root" }, section "__DATA, __objc_data", align 8
+;--- root-sub.ll
+source_filename = "root-sub.m"
+target triple = "x86_64-apple-macosx10.15.0"
-; --- RootSub (child of custom root) ---
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [8 x i8] c"RootSub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_RootSub" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_RootSub.b" = constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_RootSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_RootSub.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_RootSub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_RootSub", ptr @"OBJC_CLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_RootSub" }, section "__DATA, __objc_data", align 8
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-; --- ObjSub (child of NSObject, the external ABI-stable root) ---
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_.3 = private unnamed_addr constant [7 x i8] c"ObjSub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.3, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_ObjSub" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_ObjSub.c" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_ObjSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_ObjSub.c", ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_.3, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_ObjSub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_ObjSub", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_ObjSub" }, section "__DATA, __objc_data", align 8
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_CLASS_$_Root" = external global %struct._class_t
+@"OBJC_METACLASS_$_Root" = external global %struct._class_t
+ at RootSubName = private unnamed_addr constant [8 x i8] c"RootSub\00"
+ at IvarB = private unnamed_addr constant [2 x i8] c"b\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_RootSub.b" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_RootSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_RootSub.b", ptr @IvarB, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @RootSubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_RootSub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @RootSubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_RootSub", ptr null, ptr null }
+@"OBJC_METACLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Root", ptr @"OBJC_METACLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_RootSub" }
+@"OBJC_CLASS_$_RootSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_RootSub", ptr @"OBJC_CLASS_$_Root", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_RootSub" }
+ at RootSubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_RootSub"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @RootSubClassList], section "llvm.metadata"
-; --- Class list and compiler.used ---
-@"OBJC_LABEL_CLASS_$" = private global [3 x ptr] [ptr @"OBJC_CLASS_$_Root", ptr @"OBJC_CLASS_$_RootSub", ptr @"OBJC_CLASS_$_ObjSub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [11 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Root", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @"_OBJC_$_INSTANCE_VARIABLES_RootSub", ptr @OBJC_CLASS_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_ObjSub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
+;--- obj-sub.ll
+source_filename = "obj-sub.m"
+target triple = "x86_64-apple-macosx10.15.0"
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+%struct._objc_cache = type opaque
+%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
+%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
+%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+ at _objc_empty_cache = external global %struct._objc_cache
+@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at ObjSubName = private unnamed_addr constant [7 x i8] c"ObjSub\00"
+ at IvarC = private unnamed_addr constant [2 x i8] c"c\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_ObjSub.c" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_ObjSub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_ObjSub.c", ptr @IvarC, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @ObjSubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_ObjSub" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @ObjSubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_ObjSub", ptr null, ptr null }
+@"OBJC_METACLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_ObjSub" }
+@"OBJC_CLASS_$_ObjSub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_ObjSub", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_ObjSub" }
+ at ObjSubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_ObjSub"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @ObjSubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
index 3490c3143470a..17d9a837ad4f7 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/incomplete-hierarchy.ll
@@ -1,33 +1,22 @@
-; Test that ivar offsets are NOT promoted when the superclass is
-; external and non-stable (incomplete hierarchy).
+; Test that ivar offsets are not promoted when the superclass is external and
+; is not a known stable root.
;
; Hierarchy:
; UIViewController (external, no CLASS_RO visible)
; `- MyController
-; int myIvar; // myIvar at offset 0 (unresolvable)
+; int myIvar; // myIvar at offset 0 (unresolvable)
;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefix=CONTROLLER
-;
-; CONTROLLER: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}global i64 0
-; CONTROLLER-NOT: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}constant
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/body.ll -o %t/body.bc
-; RUN: llvm-lto2 run %t/body.bc -save-temps -o %t/out \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_MyController,plx \
-; RUN: -r=%t/body.bc,_OBJC_CLASS_$_UIViewController, \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_MyController,plx \
-; RUN: -r=%t/body.bc,_OBJC_METACLASS_$_UIViewController, \
-; RUN: -r=%t/body.bc,_OBJC_IVAR_$_MyController.myIvar,plx \
-; RUN: -r=%t/body.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=CONTROLLER
+; RUN: llvm-link %t/controller.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
+
+; CHECK: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}global i64 0
+; CHECK-NOT: @"OBJC_IVAR_$_MyController.myIvar" = {{.*}}constant
; Segments:
-; source.m - ingredients (requires Darwin SDK to regenerate)
-; gen - refresher
-; body.ll - single module used by both FullLTO and ThinLTO paths
+; source.m - ingredients
+; gen - refresher
+; controller.ll - hand-reduced IR
;--- source.m
@interface UIViewController @end
@@ -36,11 +25,9 @@
;--- gen
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm source.m -o -
-# body.ll is auto-generated from source.m
-;--- body.ll
-; ModuleID = 'source.m'
-source_filename = "source.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
+;--- controller.ll
+source_filename = "controller.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -49,28 +36,16 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_UIViewController" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [13 x i8] c"MyController\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_UIViewController", ptr @"OBJC_METACLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_MyController" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_UIViewController" = external global %struct._class_t
-@"OBJC_IVAR_$_MyController.myIvar" = global i64 0, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [7 x i8] c"myIvar\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_MyController" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_MyController.myIvar", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 0, i32 0, i32 4, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_MyController", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_MyController", ptr @"OBJC_CLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_MyController" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_MyController"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_MyController", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8}
-
-!0 = !{i32 1, !"Objective-C Version", i32 2}
-!1 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!2 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!3 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!4 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!5 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!6 = !{i32 8, !"PIC Level", i32 2}
-!7 = !{i32 7, !"uwtable", i32 2}
-!8 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_UIViewController" = external global %struct._class_t
+ at ControllerName = private unnamed_addr constant [13 x i8] c"MyController\00"
+ at IvarMyIvar = private unnamed_addr constant [7 x i8] c"myIvar\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_MyController.myIvar" = global i64 0, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_MyController" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_MyController.myIvar", ptr @IvarMyIvar, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @ControllerName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_MyController" = internal global %struct._class_ro_t { i32 0, i32 0, i32 4, ptr null, ptr @ControllerName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_MyController", ptr null, ptr null }
+@"OBJC_METACLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_UIViewController", ptr @"OBJC_METACLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_MyController" }
+@"OBJC_CLASS_$_MyController" = global %struct._class_t { ptr @"OBJC_METACLASS_$_MyController", ptr @"OBJC_CLASS_$_UIViewController", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_MyController" }
+ at ControllerClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_MyController"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @ControllerClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
index 724ff82794cd2..982ff642511f0 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/nsobject-external.ll
@@ -1,49 +1,27 @@
-; Test that external NSObject is recognized as ABI-stable root
-; and cross-TU sliding works.
+; Test that external NSObject is recognized as an ABI-stable root after
+; cross-module implementations are linked by FullLTO.
;
; Hierarchy:
; NSObject (external, ABI-stable root)
; `- Super
-; int x; // x at offset 8
-; int hidden; // hidden at offset 12 (extension)
+; int x; // x at offset 8
+; int hidden; // hidden at offset 12
; `- Sub
-; int y; // y compiled at 12, slid to 16
+; int y; // y compiled at 12, slid to 16
;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
-;
-; SUPER: @"OBJC_IVAR_$_Super.x" = {{.*}}constant i64 8
-; SUPER: @"OBJC_IVAR_$_Super.hidden" = {{.*}}constant i64 12
-; SUB: @"OBJC_IVAR_$_Sub.y" = {{.*}}constant i64 16
-; SUB: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20,
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/super.ll -o %t/super.bc
-; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
-; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_Super,plx \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_Super,plx \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.x,plx \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_Super.hidden,plx \
-; RUN: -r=%t/super.bc,__objc_empty_cache, \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Sub,plx \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_Super, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Sub,plx \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_Super, \
-; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_Sub.y,plx \
-; RUN: -r=%t/sub.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=SUPER
-; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+; RUN: llvm-link %t/super.ll %t/sub.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
+
+; CHECK: @"OBJC_IVAR_$_Super.x" = {{.*}}constant i64 8
+; CHECK: @"OBJC_IVAR_$_Super.hidden" = {{.*}}constant i64 12
+; CHECK: @"OBJC_IVAR_$_Sub.y" = {{.*}}constant i64 16
+; CHECK: @"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20,
; Segments:
; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
; gen - refresher
-; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
-; super.ll / sub.ll - per-module IR, used by ThinLTO path
+; super.ll / sub.ll - hand-reduced cross-module IR
;--- super.m
#import <objc/NSObject.h>
@@ -60,62 +38,9 @@
;--- gen
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
-llvm-link super.ll sub.ll -S -o -
-# body.ll is auto-generated by linking super.ll and sub.ll
-;--- body.ll
-; ModuleID = 'llvm-link'
-source_filename = "llvm-link"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._objc_cache = type opaque
- at llvm.compiler.used = appending global [11 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$.5"], section "llvm.metadata"
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.3 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_.3, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$.5" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
;--- super.ll
-; ModuleID = 'nsobject_super.m'
-source_filename = "nsobject_super.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "super.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -124,38 +49,24 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [6 x i8] c"Super\00"
+ at IvarX = private unnamed_addr constant [2 x i8] c"x\00"
+ at IvarHidden = private unnamed_addr constant [7 x i8] c"hidden\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Super.x" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_Super.hidden" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @IvarX, ptr @IntTy, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @IvarHidden, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Super", ptr null, ptr null }
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
;--- sub.ll
-; ModuleID = 'nsobject_sub.m'
-source_filename = "nsobject_sub.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "sub.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -164,30 +75,17 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Super" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_Super" = external global %struct._class_t
-@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SubName = private unnamed_addr constant [4 x i8] c"Sub\00"
+ at IvarY = private unnamed_addr constant [2 x i8] c"y\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @IvarY, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @SubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Sub", ptr null, ptr null }
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }
+ at SubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
index 6aa430c99db4c..bbd7721b7ddc8 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/pre-slide.ll
@@ -1,371 +1,89 @@
-; Test that a subclass gets its instanceStart slid to account for
-; hidden extension ivars in the superclass.
+; Test that FullLTO pre-slides subclass layout to account for superclass ivars
+; that were not visible to the subclass translation unit.
;
; Hierarchy:
; NSObject
; `- SuperClass
-; @property int x; // _x at offset 8
-; @property int hidden_y; // _hidden_y at offset 12 (extension)
+; int x; // x at offset 8
+; int hidden_y; // hidden_y at offset 12
; `- SubClass
-; @property int z; // _z compiled at 8, slid to 16
+; int z; // z compiled at 8, slid to 16
;
-; --- FullLTO path ---
; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=SUPER,SUB
+; RUN: llvm-link %t/super.ll %t/sub.ll -S -o %t/linked.ll
+; RUN: opt -passes=objc-constant-ivar-offset -S %t/linked.ll | FileCheck %s
;
-; SUPER: @"OBJC_IVAR_$_SuperClass._x" = {{.*}}constant i64 8
-; SUPER: @"OBJC_IVAR_$_SuperClass._hidden_y" = {{.*}}constant i64 12
-; SUB: @"OBJC_IVAR_$_SubClass._z" = {{.*}}constant i64 16
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/super.ll -o %t/super.bc
-; RUN: opt -module-summary %t/sub.ll -o %t/sub.bc
-; RUN: llvm-lto2 run %t/super.bc %t/sub.bc -save-temps -o %t/out \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_SuperClass,plx \
-; RUN: -r=%t/super.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_SuperClass,plx \
-; RUN: -r=%t/super.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_SuperClass._x,plx \
-; RUN: -r=%t/super.bc,_OBJC_IVAR_$_SuperClass._hidden_y,plx \
-; RUN: -r=%t/super.bc,__objc_empty_cache, \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_SubClass,plx \
-; RUN: -r=%t/sub.bc,_OBJC_CLASS_$_SuperClass, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_SubClass,plx \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/sub.bc,_OBJC_METACLASS_$_SuperClass, \
-; RUN: -r=%t/sub.bc,_OBJC_IVAR_$_SubClass._z,plx \
-; RUN: -r=%t/sub.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=SUPER
-; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=SUB
+; CHECK: @"OBJC_IVAR_$_SuperClass.x" = {{.*}}constant i64 8
+; CHECK: @"OBJC_IVAR_$_SuperClass.hidden_y" = {{.*}}constant i64 12
+; CHECK: @"OBJC_IVAR_$_SubClass.z" = {{.*}}constant i64 16
+; CHECK: @"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20,
; Segments:
; super.m / sub.m - ingredients (requires Darwin SDK to regenerate)
; gen - refresher
-; body.ll - merged module (llvm-link of super+sub), used by FullLTO path
-; super.ll / sub.ll - per-module IR, used by ThinLTO path
+; super.ll / sub.ll - hand-reduced cross-module IR
;--- super.m
#import <objc/NSObject.h>
- at interface SuperClass : NSObject
- at property int x;
- at end
- at interface SuperClass ()
- at property int hidden_y;
- at end
+ at interface SuperClass : NSObject { int x; } @end
+ at interface SuperClass () { int hidden_y; } @end
@implementation SuperClass @end
;--- sub.m
#import <objc/NSObject.h>
- at interface SuperClass : NSObject
- at property int x;
- at end
- at interface SubClass : SuperClass
- at property int z;
- at end
+ at interface SuperClass : NSObject @end
+ at interface SubClass : SuperClass { int z; } @end
@implementation SubClass @end
;--- gen
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) super.m -o super.ll
clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) sub.m -o sub.ll
-llvm-link super.ll sub.ll -S -o -
-# body.ll is auto-generated by linking super.ll and sub.ll
-;--- body.ll
-; ModuleID = 'llvm-link'
-source_filename = "llvm-link"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._objc_method = type { ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._prop_t = type { ptr, ptr }
-%struct._objc_cache = type opaque
-
- at llvm.compiler.used = appending global [31 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8, ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.6, ptr @OBJC_METH_VAR_TYPE_.7, ptr @OBJC_METH_VAR_NAME_.1.8, ptr @OBJC_METH_VAR_TYPE_.2.9, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.3.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_.2, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$.11"], section "llvm.metadata"
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [13 x i8] c"setHidden_y:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [4 x %struct._objc_method] } { i32 24, i32 4, [4 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass hidden_y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setHidden_y:]" }] }, section "__DATA, __objc_const", align 8
-@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.5 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.6 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_SuperClass._hidden_y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [10 x i8] c"_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._hidden_y", ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.8 = private unnamed_addr constant [14 x i8] c"Ti,V_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.9 = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [2 x %struct._prop_t] } { i32 16, i32 2, [2 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8 }, %struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
-@"OBJC_IVAR_$_SubClass._z" = hidden global i64 8, section "__DATA, __objc_ivar", align 8
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
- at OBJC_METH_VAR_NAME_.6 = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.7 = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.1.8 = private unnamed_addr constant [6 x i8] c"setZ:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2.9 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_.6, ptr @OBJC_METH_VAR_TYPE_.7, ptr @"\01-[SubClass z]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1.8, ptr @OBJC_METH_VAR_TYPE_.2.9, ptr @"\01-[SubClass setZ:]" }] }, section "__DATA, __objc_const", align 8
- at OBJC_METH_VAR_NAME_.3.3 = private unnamed_addr constant [3 x i8] c"_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._z", ptr @OBJC_METH_VAR_NAME_.3.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_.2 = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.2, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$.11" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) #0 {
- %3 = alloca ptr, align 8
- %4 = alloca ptr, align 8
- store ptr %0, ptr %3, align 8
- store ptr %1, ptr %4, align 8
- %5 = load ptr, ptr %3, align 8
- %6 = getelementptr inbounds i8, ptr %5, i64 8
- %7 = load atomic i32, ptr %6 unordered, align 4
- ret i32 %7
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
- %4 = alloca ptr, align 8
- %5 = alloca ptr, align 8
- %6 = alloca i32, align 4
- store ptr %0, ptr %4, align 8
- store ptr %1, ptr %5, align 8
- store i32 %2, ptr %6, align 4
- %7 = load ptr, ptr %4, align 8
- %8 = getelementptr inbounds i8, ptr %7, i64 8
- %9 = load i32, ptr %6, align 4
- store atomic i32 %9, ptr %8 unordered, align 4
- ret void
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal i32 @"\01-[SuperClass hidden_y]"(ptr noundef %0, ptr noundef %1) #0 {
- %3 = alloca ptr, align 8
- %4 = alloca ptr, align 8
- store ptr %0, ptr %3, align 8
- store ptr %1, ptr %4, align 8
- %5 = load ptr, ptr %3, align 8
- %6 = getelementptr inbounds i8, ptr %5, i64 12
- %7 = load atomic i32, ptr %6 unordered, align 4
- ret i32 %7
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal void @"\01-[SuperClass setHidden_y:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
- %4 = alloca ptr, align 8
- %5 = alloca ptr, align 8
- %6 = alloca i32, align 4
- store ptr %0, ptr %4, align 8
- store ptr %1, ptr %5, align 8
- store i32 %2, ptr %6, align 4
- %7 = load ptr, ptr %4, align 8
- %8 = getelementptr inbounds i8, ptr %7, i64 12
- %9 = load i32, ptr %6, align 4
- store atomic i32 %9, ptr %8 unordered, align 4
- ret void
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal i32 @"\01-[SubClass z]"(ptr noundef %0, ptr noundef %1) #0 {
- %3 = alloca ptr, align 8
- %4 = alloca ptr, align 8
- store ptr %0, ptr %3, align 8
- store ptr %1, ptr %4, align 8
- %5 = load ptr, ptr %3, align 8
- %6 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
- %7 = getelementptr inbounds i8, ptr %5, i64 %6
- %8 = load atomic i32, ptr %7 unordered, align 4
- ret i32 %8
-}
-
-; Function Attrs: noinline optnone ssp uwtable
-define internal void @"\01-[SubClass setZ:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) #0 {
- %4 = alloca ptr, align 8
- %5 = alloca ptr, align 8
- %6 = alloca i32, align 4
- store ptr %0, ptr %4, align 8
- store ptr %1, ptr %5, align 8
- store i32 %2, ptr %6, align 4
- %7 = load ptr, ptr %4, align 8
- %8 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
- %9 = getelementptr inbounds i8, ptr %7, i64 %8
- %10 = load i32, ptr %6, align 4
- store atomic i32 %10, ptr %9 unordered, align 4
- ret void
-}
-
-attributes #0 = { noinline optnone ssp uwtable "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="penryn" "target-features"="+cmov,+cx16,+cx8,+fxsr,+mmx,+sahf,+sse,+sse2,+sse3,+sse4.1,+ssse3,+x87" "tune-cpu"="generic" }
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
-!10 = !{}
;--- super.ll
-; ModuleID = 'preslide_super.m'
-source_filename = "preslide_super.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "super.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._objc_method = type { ptr, ptr, ptr }
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._prop_t = type { ptr, ptr }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [11 x i8] c"SuperClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setX:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [13 x i8] c"setHidden_y:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SuperClass" = internal global { i32, i32, [4 x %struct._objc_method] } { i32 24, i32 4, [4 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass x]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setX:]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SuperClass hidden_y]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SuperClass setHidden_y:]" }] }, section "__DATA, __objc_const", align 8
-@"OBJC_IVAR_$_SuperClass._x" = hidden constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.5 = private unnamed_addr constant [3 x i8] c"_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.6 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_SuperClass._hidden_y" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.7 = private unnamed_addr constant [10 x i8] c"_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SuperClass" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._x", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass._hidden_y", ptr @OBJC_METH_VAR_NAME_.7, ptr @OBJC_METH_VAR_TYPE_.6, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [9 x i8] c"hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.8 = private unnamed_addr constant [14 x i8] c"Ti,V_hidden_y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.9 = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.10 = private unnamed_addr constant [7 x i8] c"Ti,V_x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SuperClass" = internal global { i32, i32, [2 x %struct._prop_t] } { i32 16, i32 2, [2 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8 }, %struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SuperClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [18 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_NAME_.4, ptr @"_OBJC_$_INSTANCE_METHODS_SuperClass", ptr @OBJC_METH_VAR_NAME_.5, ptr @OBJC_METH_VAR_TYPE_.6, ptr @OBJC_METH_VAR_NAME_.7, ptr @"_OBJC_$_INSTANCE_VARIABLES_SuperClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.8, ptr @OBJC_PROP_NAME_ATTR_.9, ptr @OBJC_PROP_NAME_ATTR_.10, ptr @"_OBJC_$_PROP_LIST_SuperClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-define internal i32 @"\01-[SuperClass x]"(ptr noundef %0, ptr noundef %1) {
- %3 = getelementptr inbounds i8, ptr %0, i64 8
- %4 = load atomic i32, ptr %3 unordered, align 4
- ret i32 %4
-}
-
-define internal void @"\01-[SuperClass setX:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
- %4 = getelementptr inbounds i8, ptr %0, i64 8
- store atomic i32 %2, ptr %4 unordered, align 4
- ret void
-}
-
-define internal i32 @"\01-[SuperClass hidden_y]"(ptr noundef %0, ptr noundef %1) {
- %3 = getelementptr inbounds i8, ptr %0, i64 12
- %4 = load atomic i32, ptr %3 unordered, align 4
- ret i32 %4
-}
-
-define internal void @"\01-[SuperClass setHidden_y:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
- %4 = getelementptr inbounds i8, ptr %0, i64 12
- store atomic i32 %2, ptr %4 unordered, align 4
- ret void
-}
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [11 x i8] c"SuperClass\00"
+ at IvarX = private unnamed_addr constant [2 x i8] c"x\00"
+ at IvarHidden = private unnamed_addr constant [9 x i8] c"hidden_y\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_SuperClass.x" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_SuperClass.hidden_y" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_SuperClass" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass.x", ptr @IvarX, ptr @IntTy, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_SuperClass.hidden_y", ptr @IvarHidden, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_SuperClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_SuperClass", ptr null, ptr null }
+@"OBJC_METACLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SuperClass" }
+@"OBJC_CLASS_$_SuperClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SuperClass", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SuperClass" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SuperClass"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
;--- sub.ll
-; ModuleID = 'preslide_sub.m'
-source_filename = "preslide_sub.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "sub.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._objc_method = type { ptr, ptr, ptr }
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._prop_t = type { ptr, ptr }
-@"OBJC_IVAR_$_SubClass._z" = hidden global i64 8, section "__DATA, __objc_ivar", align 8
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_SuperClass" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [9 x i8] c"SubClass\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_SuperClass" = external global %struct._class_t
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [8 x i8] c"i16 at 0:8\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [6 x i8] c"setZ:\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.2 = private unnamed_addr constant [11 x i8] c"v20 at 0:8i16\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_METHODS_SubClass" = internal global { i32, i32, [2 x %struct._objc_method] } { i32 24, i32 2, [2 x %struct._objc_method] [%struct._objc_method { ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"\01-[SubClass z]" }, %struct._objc_method { ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"\01-[SubClass setZ:]" }] }, section "__DATA, __objc_const", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [3 x i8] c"_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.4 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass._z", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
- at OBJC_PROP_NAME_ATTR_ = private unnamed_addr constant [2 x i8] c"z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_PROP_NAME_ATTR_.5 = private unnamed_addr constant [7 x i8] c"Ti,V_z\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_PROP_LIST_SubClass" = internal global { i32, i32, [1 x %struct._prop_t] } { i32 16, i32 1, [1 x %struct._prop_t] [%struct._prop_t { ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr null, ptr @"_OBJC_$_PROP_LIST_SubClass" }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [13 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_.2, ptr @"_OBJC_$_INSTANCE_METHODS_SubClass", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_.4, ptr @"_OBJC_$_INSTANCE_VARIABLES_SubClass", ptr @OBJC_PROP_NAME_ATTR_, ptr @OBJC_PROP_NAME_ATTR_.5, ptr @"_OBJC_$_PROP_LIST_SubClass", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-define internal i32 @"\01-[SubClass z]"(ptr noundef %0, ptr noundef %1) {
- %3 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
- %4 = getelementptr inbounds i8, ptr %0, i64 %3
- %5 = load atomic i32, ptr %4 unordered, align 4
- ret i32 %5
-}
-
-define internal void @"\01-[SubClass setZ:]"(ptr noundef %0, ptr noundef %1, i32 noundef %2) {
- %4 = load i64, ptr @"OBJC_IVAR_$_SubClass._z", align 8, !invariant.load !10
- %5 = getelementptr inbounds i8, ptr %0, i64 %4
- store atomic i32 %2, ptr %5 unordered, align 4
- ret void
-}
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
-!10 = !{}
+@"OBJC_METACLASS_$_SuperClass" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SubName = private unnamed_addr constant [9 x i8] c"SubClass\00"
+ at IvarZ = private unnamed_addr constant [2 x i8] c"z\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_SubClass.z" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_SubClass" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_SubClass.z", ptr @IvarZ, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_SubClass" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @SubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_SubClass", ptr null, ptr null }
+@"OBJC_METACLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_SubClass" }
+@"OBJC_CLASS_$_SubClass" = global %struct._class_t { ptr @"OBJC_METACLASS_$_SubClass", ptr @"OBJC_CLASS_$_SuperClass", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_SubClass" }
+ at SubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_SubClass"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
index 94a9d9f895b9f..5b64489b56610 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/summary-serialization.ll
@@ -15,24 +15,8 @@
; op2=instanceStart(8), op3=instanceSize(16), op4=maxIvarAlignment(4)
; CHECK: <OBJC_CLASS_INFO op0={{[0-9]+}} op1={{[0-9]+}} op2=8 op3=16 op4=4/>
-; Segments:
-; source.m - ingredients (requires Darwin SDK to regenerate)
-; gen - refresher
-; body.ll - single module used by both FullLTO and ThinLTO paths
-
-;--- source.m
-#import <objc/NSObject.h>
- at interface Super : NSObject { int x; } @end
- at interface Super () { int hidden; } @end
- at implementation Super @end
-
-;--- gen
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) source.m -o -
-# body.ll is auto-generated from source.m
;--- body.ll
-; ModuleID = 'source.m'
-source_filename = "source.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+source_filename = "summary.m"
target triple = "x86_64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
@@ -41,31 +25,18 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [6 x i8] c"Super\00"
+ at IvarX = private unnamed_addr constant [2 x i8] c"x\00"
+ at IvarHidden = private unnamed_addr constant [7 x i8] c"hidden\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Super.x" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_Super.hidden" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @IvarX, ptr @IntTy, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @IvarHidden, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Super", ptr null, ptr null }
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
index f418cbfbe68ad..f16ab7302b660 100644
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
+++ b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto-cross-module.ll
@@ -55,16 +55,11 @@
@implementation Sub @end
;--- gen
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Super.m -o super.ll
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Sub.m -o sub.ll
-cat super.ll
-echo ';--- sub.ll'
-cat sub.ll
+clang -target arm64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Super.m -o super.ll
+clang -target arm64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) Sub.m -o sub.ll
;--- super.ll
-; ModuleID = 'Super.m'
-source_filename = "Super.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
+source_filename = "super.m"
+target triple = "arm64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
@@ -72,39 +67,24 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [6 x i8] c"Super\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Super.x" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"x\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"OBJC_IVAR_$_Super.hidden" = hidden constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.1 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @OBJC_METH_VAR_NAME_.1, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [6 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @OBJC_METH_VAR_NAME_.1, ptr @"_OBJC_$_INSTANCE_VARIABLES_Super", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SuperName = private unnamed_addr constant [6 x i8] c"Super\00"
+ at IvarX = private unnamed_addr constant [2 x i8] c"x\00"
+ at IvarHidden = private unnamed_addr constant [7 x i8] c"hidden\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
+@"OBJC_IVAR_$_Super.x" = global i64 8, section "__DATA,__objc_ivar", align 8
+@"OBJC_IVAR_$_Super.hidden" = global i64 12, section "__DATA,__objc_ivar", align 8
+@"_OBJC_IVARS_$_Super" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Super.x", ptr @IvarX, ptr @IntTy, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Super.hidden", ptr @IvarHidden, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SuperName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Super" = internal global %struct._class_ro_t { i32 0, i32 8, i32 16, ptr null, ptr @SuperName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Super", ptr null, ptr null }
+@"OBJC_METACLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Super" }
+@"OBJC_CLASS_$_Super" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Super", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Super" }
+ at SuperClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Super"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SuperClassList], section "llvm.metadata"
;--- sub.ll
-; ModuleID = 'Sub.m'
-source_filename = "Sub.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
+source_filename = "sub.m"
+target triple = "arm64-apple-macosx10.15.0"
%struct._objc_cache = type opaque
%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
@@ -112,30 +92,17 @@ target triple = "x86_64-apple-macosx10.15.0"
%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
@_objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Super" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [4 x i8] c"Sub\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
@"OBJC_CLASS_$_Super" = external global %struct._class_t
+@"OBJC_METACLASS_$_Super" = external global %struct._class_t
+@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
+ at SubName = private unnamed_addr constant [4 x i8] c"Sub\00"
+ at IvarY = private unnamed_addr constant [2 x i8] c"y\00"
+ at IntTy = private unnamed_addr constant [2 x i8] c"i\00"
@"OBJC_IVAR_$_Sub.y" = global i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"y\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Sub", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
+@"_OBJC_IVARS_$_Sub" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Sub.y", ptr @IvarY, ptr @IntTy, i32 2, i32 4 }] }
+@"_OBJC_METACLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @SubName, ptr null, ptr null, ptr null, ptr null, ptr null }
+@"_OBJC_CLASS_RO_$_Sub" = internal global %struct._class_ro_t { i32 0, i32 12, i32 16, ptr null, ptr @SubName, ptr null, ptr null, ptr @"_OBJC_IVARS_$_Sub", ptr null, ptr null }
+@"OBJC_METACLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Sub" }
+@"OBJC_CLASS_$_Sub" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Sub", ptr @"OBJC_CLASS_$_Super", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Sub" }
+ at SubClassList = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Sub"], section "__DATA,__objc_classlist,regular,no_dead_strip"
+ at llvm.compiler.used = appending global [1 x ptr] [ptr @SubClassList], section "llvm.metadata"
diff --git a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll b/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
deleted file mode 100644
index 7fb77ecd2ba4e..0000000000000
--- a/llvm/test/Transforms/ObjCConstantIvarOffset/thinlto.ll
+++ /dev/null
@@ -1,218 +0,0 @@
-; Test multi-level hierarchy with cascading slide across three levels
-; in a single merged module.
-;
-; Hierarchy:
-; NSObject
-; `- Base
-; int a; // a at offset 8
-; `- Middle
-; int b; // b at offset 12
-; int hidden; // hidden at offset 16 (extension)
-; `- Leaf
-; int c; // c compiled at 16, slid to 20
-;
-; --- FullLTO path ---
-; RUN: rm -rf %t && split-file %s %t
-; RUN: opt -passes=objc-constant-ivar-offset -S %t/body.ll | FileCheck %s --check-prefixes=MIDDLE,LEAF
-;
-; MIDDLE: @"OBJC_IVAR_$_Base.a" = {{.*}}constant i64 8
-; MIDDLE: @"OBJC_IVAR_$_Middle.b" = {{.*}}constant i64 12
-; MIDDLE: @"OBJC_IVAR_$_Middle.hidden" = {{.*}}constant i64 16
-; LEAF: @"OBJC_IVAR_$_Leaf.c" = {{.*}}constant i64 20
-; LEAF: @"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 20, i32 24,
-;
-; --- ThinLTO path ---
-; RUN: opt -module-summary %t/middle.ll -o %t/middle.bc
-; RUN: opt -module-summary %t/leaf.ll -o %t/leaf.bc
-; RUN: llvm-lto2 run %t/middle.bc %t/leaf.bc -save-temps -o %t/out \
-; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_Base,plx \
-; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_Middle,plx \
-; RUN: -r=%t/middle.bc,_OBJC_CLASS_$_NSObject, \
-; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_Base,plx \
-; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_Middle,plx \
-; RUN: -r=%t/middle.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Base.a,plx \
-; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Middle.b,plx \
-; RUN: -r=%t/middle.bc,_OBJC_IVAR_$_Middle.hidden,plx \
-; RUN: -r=%t/middle.bc,__objc_empty_cache, \
-; RUN: -r=%t/leaf.bc,_OBJC_CLASS_$_Leaf,plx \
-; RUN: -r=%t/leaf.bc,_OBJC_CLASS_$_Middle, \
-; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_Leaf,plx \
-; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_NSObject, \
-; RUN: -r=%t/leaf.bc,_OBJC_METACLASS_$_Middle, \
-; RUN: -r=%t/leaf.bc,_OBJC_IVAR_$_Leaf.c,plx \
-; RUN: -r=%t/leaf.bc,__objc_empty_cache,
-; RUN: llvm-dis %t/out.1.4.opt.bc -o - | FileCheck %s --check-prefix=MIDDLE
-; RUN: llvm-dis %t/out.2.4.opt.bc -o - | FileCheck %s --check-prefix=LEAF
-
-; Segments:
-; middle.m / leaf.m - ingredients (requires Darwin SDK to regenerate)
-; gen - refresher
-; body.ll - merged module (llvm-link of middle+leaf), used by FullLTO path
-; middle.ll / leaf.ll - per-module IR, used by ThinLTO path
-
-;--- middle.m
-#import <objc/NSObject.h>
- at interface Base : NSObject { int a; } @end
- at interface Middle : Base { int b; } @end
- at interface Middle () { int hidden; } @end
- at implementation Base @end
- at implementation Middle @end
-
-;--- leaf.m
-#import <objc/NSObject.h>
- at interface Base : NSObject { int a; } @end
- at interface Middle : Base { int b; } @end
- at interface Leaf : Middle { int c; } @end
- at implementation Leaf @end
-
-;--- gen
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) middle.m -o middle.ll
-clang -target x86_64-apple-macosx10.15 -fobjc-runtime=macosx-10.15 -S -emit-llvm -isysroot $(xcrun --show-sdk-path) leaf.m -o leaf.ll
-llvm-link middle.ll leaf.ll -S -o -
-# body.ll is auto-generated by linking middle.ll and leaf.ll
-;--- body.ll
-; ModuleID = 'llvm-link'
-source_filename = "llvm-link"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-%struct._objc_cache = type opaque
-
- at llvm.compiler.used = appending global [14 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr @"OBJC_LABEL_CLASS_$", ptr @OBJC_CLASS_NAME_.2, ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.5, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr @"OBJC_LABEL_CLASS_$.7"], section "llvm.metadata"
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Base\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Base.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Base" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Base.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Base", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [7 x i8] c"Middle\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_IVAR_$_Middle.b" = constant i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"OBJC_IVAR_$_Middle.hidden" = hidden constant i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Middle" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.hidden", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 0, i32 12, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_Base", ptr @"OBJC_CLASS_$_Middle"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.2 = private unnamed_addr constant [5 x i8] c"Leaf\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.2, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Middle", ptr @"OBJC_CLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_Leaf.c" = global i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.4 = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_.5 = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Leaf" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Leaf.c", ptr @OBJC_METH_VAR_NAME_.4, ptr @OBJC_METH_VAR_TYPE_.5, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.2, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Leaf", ptr @"OBJC_CLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$.7" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Leaf"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
-;--- middle.ll
-; ModuleID = 'thinlto_middle.m'
-source_filename = "thinlto_middle.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._objc_cache = type opaque
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Base\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_IVAR_$_Base.a" = constant i64 8, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"a\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Base" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Base.a", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Base" = internal global %struct._class_ro_t { i32 0, i32 8, i32 12, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Base" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Base", ptr @"OBJC_CLASS_$_NSObject", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Base" }, section "__DATA, __objc_data", align 8
- at OBJC_CLASS_NAME_.1 = private unnamed_addr constant [7 x i8] c"Middle\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
-@"OBJC_IVAR_$_Middle.b" = global i64 12, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.2 = private unnamed_addr constant [2 x i8] c"b\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"OBJC_IVAR_$_Middle.hidden" = hidden global i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_.3 = private unnamed_addr constant [7 x i8] c"hidden\00", section "__TEXT,__objc_methname,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Middle" = internal global { i32, i32, [2 x %struct._ivar_t] } { i32 32, i32 2, [2 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.b", ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }, %struct._ivar_t { ptr @"OBJC_IVAR_$_Middle.hidden", ptr @OBJC_METH_VAR_NAME_.3, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Middle" = internal global %struct._class_ro_t { i32 0, i32 12, i32 20, ptr null, ptr @OBJC_CLASS_NAME_.1, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Middle" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Middle", ptr @"OBJC_CLASS_$_Base", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Middle" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [2 x ptr] [ptr @"OBJC_CLASS_$_Base", ptr @"OBJC_CLASS_$_Middle"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [9 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Base", ptr @OBJC_CLASS_NAME_.1, ptr @OBJC_METH_VAR_NAME_.2, ptr @OBJC_METH_VAR_NAME_.3, ptr @"_OBJC_$_INSTANCE_VARIABLES_Middle", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
-;--- leaf.ll
-; ModuleID = 'thinlto_leaf.m'
-source_filename = "thinlto_leaf.m"
-target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
-target triple = "x86_64-apple-macosx10.15.0"
-
-%struct._objc_cache = type opaque
-%struct._class_t = type { ptr, ptr, ptr, ptr, ptr }
-%struct._class_ro_t = type { i32, i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, ptr }
-%struct._ivar_t = type { ptr, ptr, ptr, i32, i32 }
-
- at _objc_empty_cache = external global %struct._objc_cache
-@"OBJC_METACLASS_$_NSObject" = external global %struct._class_t
-@"OBJC_METACLASS_$_Middle" = external global %struct._class_t
- at OBJC_CLASS_NAME_ = private unnamed_addr constant [5 x i8] c"Leaf\00", section "__TEXT,__objc_classname,cstring_literals", align 1
-@"_OBJC_METACLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 1, i32 40, i32 40, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr null, ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_METACLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_NSObject", ptr @"OBJC_METACLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_METACLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
-@"OBJC_CLASS_$_Middle" = external global %struct._class_t
-@"OBJC_IVAR_$_Leaf.c" = global i64 16, section "__DATA, __objc_ivar", align 8
- at OBJC_METH_VAR_NAME_ = private unnamed_addr constant [2 x i8] c"c\00", section "__TEXT,__objc_methname,cstring_literals", align 1
- at OBJC_METH_VAR_TYPE_ = private unnamed_addr constant [2 x i8] c"i\00", section "__TEXT,__objc_methtype,cstring_literals", align 1
-@"_OBJC_$_INSTANCE_VARIABLES_Leaf" = internal global { i32, i32, [1 x %struct._ivar_t] } { i32 32, i32 1, [1 x %struct._ivar_t] [%struct._ivar_t { ptr @"OBJC_IVAR_$_Leaf.c", ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, i32 2, i32 4 }] }, section "__DATA, __objc_const", align 8
-@"_OBJC_CLASS_RO_$_Leaf" = internal global %struct._class_ro_t { i32 0, i32 16, i32 20, ptr null, ptr @OBJC_CLASS_NAME_, ptr null, ptr null, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr null, ptr null }, section "__DATA, __objc_const", align 8
-@"OBJC_CLASS_$_Leaf" = global %struct._class_t { ptr @"OBJC_METACLASS_$_Leaf", ptr @"OBJC_CLASS_$_Middle", ptr @_objc_empty_cache, ptr null, ptr @"_OBJC_CLASS_RO_$_Leaf" }, section "__DATA, __objc_data", align 8
-@"OBJC_LABEL_CLASS_$" = private global [1 x ptr] [ptr @"OBJC_CLASS_$_Leaf"], section "__DATA,__objc_classlist,regular,no_dead_strip", align 8
- at llvm.compiler.used = appending global [5 x ptr] [ptr @OBJC_CLASS_NAME_, ptr @OBJC_METH_VAR_NAME_, ptr @OBJC_METH_VAR_TYPE_, ptr @"_OBJC_$_INSTANCE_VARIABLES_Leaf", ptr @"OBJC_LABEL_CLASS_$"], section "llvm.metadata"
-
-!llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9}
-
-!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 26, i32 2]}
-!1 = !{i32 1, !"Objective-C Version", i32 2}
-!2 = !{i32 1, !"Objective-C Image Info Version", i32 0}
-!3 = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"}
-!4 = !{i32 1, !"Objective-C Garbage Collection", i8 0}
-!5 = !{i32 1, !"Objective-C Class Properties", i32 64}
-!6 = !{i32 1, !"Objective-C Enforce ClassRO Pointer Signing", i8 0}
-!7 = !{i32 8, !"PIC Level", i32 2}
-!8 = !{i32 7, !"uwtable", i32 2}
-!9 = !{i32 7, !"frame-pointer", i32 2}
More information about the cfe-commits
mailing list