[clang] [llvm] [X86][APX] Combine MOVABS+JMP to JMPABS when in no-PIC large code model (PR #186402)
Phoebe Wang via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 15 23:08:04 PDT 2026
https://github.com/phoebewang updated https://github.com/llvm/llvm-project/pull/186402
>From 0b76fbc26aee9ff67b92a7e3f9969bf357d40e75 Mon Sep 17 00:00:00 2001
From: Phoebe Wang <phoebe.wang at intel.com>
Date: Fri, 13 Mar 2026 21:13:23 +0800
Subject: [PATCH 1/2] [X86][APX] Combine MOVABS+JMP to JMPABS when in no-PIC
large code model
---
clang/include/clang/Options/Options.td | 4 ++--
clang/lib/Basic/Targets/X86.cpp | 8 +++++++-
clang/lib/Basic/Targets/X86.h | 1 +
clang/lib/Driver/ToolChains/Arch/X86.cpp | 6 +++---
clang/test/Driver/cl-x86-flags.c | 8 ++++----
clang/test/Driver/x86-target-features.c | 6 ++++--
clang/test/Preprocessor/predefined-arch-macros.c | 4 ++++
clang/test/Preprocessor/x86_target_features.c | 4 +++-
.../include/llvm/TargetParser/X86TargetParser.def | 1 +
llvm/lib/Target/X86/X86.td | 4 ++++
llvm/lib/Target/X86/X86InstrCompiler.td | 8 ++++++++
llvm/lib/Target/X86/X86InstrPredicates.td | 1 +
llvm/lib/Target/X86/X86MCInstLower.cpp | 14 +++++++++++---
llvm/lib/Target/X86/X86Subtarget.cpp | 5 +++--
llvm/lib/TargetParser/Host.cpp | 1 +
llvm/lib/TargetParser/X86TargetParser.cpp | 9 +++++----
llvm/test/CodeGen/X86/tailcc-largecode.ll | 15 ++++++++++-----
17 files changed, 72 insertions(+), 27 deletions(-)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 4bbdd9c8c0e58..2f780f4ac6163 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -7168,9 +7168,9 @@ def mno_gather : Flag<["-"], "mno-gather">, Group<m_Group>,
def mno_scatter : Flag<["-"], "mno-scatter">, Group<m_Group>,
HelpText<"Disable generation of scatter instructions in auto-vectorization(x86 only)">;
def mapx_features_EQ : CommaJoined<["-"], "mapx-features=">, Group<m_x86_Features_Group>,
- HelpText<"Enable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">, Visibility<[ClangOption, CLOption, FlangOption]>;
+ HelpText<"Enable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu,jmpabs">, Visibility<[ClangOption, CLOption, FlangOption]>;
def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group<m_x86_Features_Group>,
- HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu">, Visibility<[ClangOption, CLOption, FlangOption]>;
+ HelpText<"Disable features of APX">, Values<"egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu,jmpabs">, Visibility<[ClangOption, CLOption, FlangOption]>;
def mapxf : Flag<["-"], "mapxf">, Group<m_x86_Features_Group>;
def mno_apxf : Flag<["-"], "mno-apxf">, Group<m_x86_Features_Group>;
def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>,
diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp
index 6f88a428b1230..cb941c94c84a7 100644
--- a/clang/lib/Basic/Targets/X86.cpp
+++ b/clang/lib/Basic/Targets/X86.cpp
@@ -451,6 +451,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasCF = true;
} else if (Feature == "+zu") {
HasZU = true;
+ } else if (Feature == "+jmpabs") {
+ HasJMPABS = true;
} else if (Feature == "+branch-hint") {
HasBranchHint = true;
}
@@ -975,7 +977,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__CF__");
if (HasZU)
Builder.defineMacro("__ZU__");
- if (HasEGPR && HasNDD && HasCCMP && HasNF && HasZU)
+ if (HasJMPABS)
+ Builder.defineMacro("__JMPABS__");
+ if (HasEGPR && HasNDD && HasCCMP && HasNF && HasZU && HasJMPABS)
if (getTriple().isOSWindows() || (HasPush2Pop2 && HasPPX))
Builder.defineMacro("__APX_F__");
if (HasEGPR && HasInlineAsmUseGPR32)
@@ -1177,6 +1181,7 @@ bool X86TargetInfo::isValidFeatureName(StringRef Name) const {
.Case("nf", true)
.Case("cf", true)
.Case("zu", true)
+ .Case("jmpabs", true)
.Default(false);
}
@@ -1300,6 +1305,7 @@ bool X86TargetInfo::hasFeature(StringRef Feature) const {
.Case("nf", HasNF)
.Case("cf", HasCF)
.Case("zu", HasZU)
+ .Case("jmpabs", HasJMPABS)
.Case("branch-hint", HasBranchHint)
.Default(false);
}
diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h
index f99bbf363458f..20090757c10c7 100644
--- a/clang/lib/Basic/Targets/X86.h
+++ b/clang/lib/Basic/Targets/X86.h
@@ -177,6 +177,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasNF = false;
bool HasCF = false;
bool HasZU = false;
+ bool HasJMPABS = false;
bool HasInlineAsmUseGPR32 = false;
bool HasBranchHint = false;
diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp
index c113da6733370..5891b56999420 100644
--- a/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -265,13 +265,13 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
if (IsNegative) {
EGPROpt = EGPRFeature::Disabled;
Features.insert(Features.end(),
- {"-egpr", "-ndd", "-ccmp", "-nf", "-zu"});
+ {"-egpr", "-ndd", "-ccmp", "-nf", "-zu", "-jmpabs"});
if (!Triple.isOSWindows())
Features.insert(Features.end(), {"-push2pop2", "-ppx"});
} else {
EGPROpt = EGPRFeature::Enabled;
Features.insert(Features.end(),
- {"+egpr", "+ndd", "+ccmp", "+nf", "+zu"});
+ {"+egpr", "+ndd", "+ccmp", "+nf", "+zu", "+jmpabs"});
if (!Triple.isOSWindows())
Features.insert(Features.end(), {"+push2pop2", "+ppx"});
@@ -291,7 +291,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
for (StringRef Value : A->getValues()) {
if (Value != "egpr" && Value != "push2pop2" && Value != "ppx" &&
Value != "ndd" && Value != "ccmp" && Value != "nf" &&
- Value != "cf" && Value != "zu")
+ Value != "cf" && Value != "zu" && Value != "jmpabs")
D.Diag(clang::diag::err_drv_unsupported_option_argument)
<< A->getSpelling() << Value;
diff --git a/clang/test/Driver/cl-x86-flags.c b/clang/test/Driver/cl-x86-flags.c
index 5b32f17774e27..05960dd07612b 100644
--- a/clang/test/Driver/cl-x86-flags.c
+++ b/clang/test/Driver/cl-x86-flags.c
@@ -222,7 +222,7 @@ void f(void) {
// RUN: %clang_cl --target=x86_64-pc-windows -mapxf -### -- 2>&1 %s | FileCheck -check-prefix=APXF %s
// RUN: %clang_cl --target=x86_64-pc-windows -mapxf -mno-apxf -### -- 2>&1 %s | FileCheck -check-prefix=NO-APXF %s
-// RUN: %clang_cl --target=x86_64-pc-windows -mapx-features=egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu -### -- 2>&1 %s | FileCheck -check-prefix=APXALL %s
-// APXF: "-target-feature" "+egpr" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+zu"
-// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" "-target-feature" "-zu"
-// APXALL: "-target-feature" "+egpr" "-target-feature" "+push2pop2" "-target-feature" "+ppx" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+cf" "-target-feature" "+zu"
+// RUN: %clang_cl --target=x86_64-pc-windows -mapx-features=egpr,push2pop2,ppx,ndd,ccmp,nf,cf,zu,jmpabs -### -- 2>&1 %s | FileCheck -check-prefix=APXALL %s
+// APXF: "-target-feature" "+egpr" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+zu" "-target-feature" "+jmpabs"
+// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" "-target-feature" "-zu" "-target-feature" "-jmpabs"
+// APXALL: "-target-feature" "+egpr" "-target-feature" "+push2pop2" "-target-feature" "+ppx" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+cf" "-target-feature" "+zu" "-target-feature" "+jmpabs"
diff --git a/clang/test/Driver/x86-target-features.c b/clang/test/Driver/x86-target-features.c
index 99eef8e4da172..b6ca38c92003f 100644
--- a/clang/test/Driver/x86-target-features.c
+++ b/clang/test/Driver/x86-target-features.c
@@ -444,8 +444,8 @@
// RUN: %clang --target=x86_64-unknown-linux-gnu -mno-apxf -mapxf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=APXF %s
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapxf -mno-apxf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NO-APXF %s
//
-// APXF: "-target-feature" "+egpr" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+zu" "-target-feature" "+push2pop2" "-target-feature" "+ppx"
-// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" "-target-feature" "-zu" "-target-feature" "-push2pop2" "-target-feature" "-ppx"
+// APXF: "-target-feature" "+egpr" "-target-feature" "+ndd" "-target-feature" "+ccmp" "-target-feature" "+nf" "-target-feature" "+zu" "-target-feature" "+jmpabs" "-target-feature" "+push2pop2" "-target-feature" "+ppx"
+// NO-APXF: "-target-feature" "-egpr" "-target-feature" "-ndd" "-target-feature" "-ccmp" "-target-feature" "-nf" "-target-feature" "-zu" "-target-feature" "-jmpabs" "-target-feature" "-push2pop2" "-target-feature" "-ppx"
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=egpr %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR %s
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=push2pop2 %s -### -o %t.o 2>&1 | FileCheck -check-prefix=PUSH2POP2 %s
@@ -455,6 +455,7 @@
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=nf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=NF %s
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=cf %s -### -o %t.o 2>&1 | FileCheck -check-prefix=CF %s
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=zu %s -### -o %t.o 2>&1 | FileCheck -check-prefix=ZU %s
+// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=jmpabs %s -### -o %t.o 2>&1 | FileCheck -check-prefix=JMPABS %s
// EGPR: "-target-feature" "+egpr"
// PUSH2POP2: "-target-feature" "+push2pop2"
// PPX: "-target-feature" "+ppx"
@@ -463,6 +464,7 @@
// NF: "-target-feature" "+nf"
// CF: "-target-feature" "+cf"
// ZU: "-target-feature" "+zu"
+// JMPABS: "-target-feature" "+jmpabs"
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=egpr,ndd %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR-NDD %s
// RUN: %clang --target=x86_64-unknown-linux-gnu -mapx-features=egpr -mapx-features=ndd %s -### -o %t.o 2>&1 | FileCheck -check-prefix=EGPR-NDD %s
diff --git a/clang/test/Preprocessor/predefined-arch-macros.c b/clang/test/Preprocessor/predefined-arch-macros.c
index be94eb064cf91..8ca7a18d852d4 100644
--- a/clang/test/Preprocessor/predefined-arch-macros.c
+++ b/clang/test/Preprocessor/predefined-arch-macros.c
@@ -1876,6 +1876,7 @@
// CHECK_GNR_M32: #define __FMA__ 1
// CHECK_GNR_M32: #define __GFNI__ 1
// CHECK_GNR_M32: #define __INVPCID__ 1
+// CHECK_DMR_M32: #define __JMPABS__ 1
// CHECK_GNR_M32: #define __LZCNT__ 1
// CHECK_GNR_M32: #define __MMX__ 1
// CHECK_GNR_M32: #define __MOVBE__ 1
@@ -1981,6 +1982,7 @@
// CHECK_GNR_M64: #define __FMA__ 1
// CHECK_GNR_M64: #define __GFNI__ 1
// CHECK_GNR_M64: #define __INVPCID__ 1
+// CHECK_DMR_M64: #define __JMPABS__ 1
// CHECK_GNR_M64: #define __LZCNT__ 1
// CHECK_GNR_M64: #define __MMX__ 1
// CHECK_GNR_M64: #define __MOVBE__ 1
@@ -2576,6 +2578,7 @@
// CHECK_ARL_M32: #define __GFNI__ 1
// CHECK_ARL_M32: #define __HRESET__ 1
// CHECK_ARL_M32: #define __INVPCID__ 1
+// CHECK_NVL_M32: #define __JMPABS__ 1
// CHECK_KL_M32: #define __KL__ 1
// CHECK_NKL_M32-NOT: __KL__
// CHECK_ARL_M32: #define __LZCNT__ 1
@@ -2709,6 +2712,7 @@
// CHECK_ARL_M64: #define __GFNI__ 1
// CHECK_ARL_M64: #define __HRESET__ 1
// CHECK_ARL_M64: #define __INVPCID__ 1
+// CHECK_NVL_M64: #define __JMPABS__ 1
// CHECK_KL_M64: #define __KL__ 1
// CHECK_NKL_M64-NOT: __KL__
// CHECK_ARL_M64: #define __LZCNT__ 1
diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c
index 78f8b19459c2f..daf81d71e41c0 100644
--- a/clang/test/Preprocessor/x86_target_features.c
+++ b/clang/test/Preprocessor/x86_target_features.c
@@ -738,11 +738,13 @@
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=nf -x c -E -dM -o - %s | FileCheck --check-prefix=NF %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=cf -x c -E -dM -o - %s | FileCheck --check-prefix=CF %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=zu -x c -E -dM -o - %s | FileCheck --check-prefix=ZU %s
-// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD,CCMP,NF,ZU,APXF %s
+// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=jmpabs -x c -E -dM -o - %s | FileCheck --check-prefix=JMPABS %s
+// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapxf -x c -E -dM -o - %s | FileCheck --check-prefixes=EGPR,PUSH2POP2,PPX,NDD,CCMP,NF,ZU,JMPABS,APXF %s
// APXF: #define __APX_F__ 1
// CCMP: #define __CCMP__ 1
// CF: #define __CF__ 1
// EGPR: #define __EGPR__ 1
+// JMPABS: #define __JMPABS__ 1
// NDD: #define __NDD__ 1
// NF: #define __NF__ 1
// PPX: #define __PPX__ 1
diff --git a/llvm/include/llvm/TargetParser/X86TargetParser.def b/llvm/include/llvm/TargetParser/X86TargetParser.def
index bc05452400458..db03fc855df5a 100644
--- a/llvm/include/llvm/TargetParser/X86TargetParser.def
+++ b/llvm/include/llvm/TargetParser/X86TargetParser.def
@@ -268,6 +268,7 @@ X86_FEATURE (PPX, "ppx")
X86_FEATURE (NDD, "ndd")
X86_FEATURE (EGPR, "egpr")
X86_FEATURE (ZU, "zu")
+X86_FEATURE (JMPABS, "jmpabs")
// These features aren't really CPU features, but the frontend can set them.
X86_FEATURE (RETPOLINE_EXTERNAL_THUNK, "retpoline-external-thunk")
diff --git a/llvm/lib/Target/X86/X86.td b/llvm/lib/Target/X86/X86.td
index eca763735c315..cac10d3ca0847 100644
--- a/llvm/lib/Target/X86/X86.td
+++ b/llvm/lib/Target/X86/X86.td
@@ -371,6 +371,8 @@ def FeatureCF : SubtargetFeature<"cf", "HasCF", "true",
"Support conditional faulting">;
def FeatureZU : SubtargetFeature<"zu", "HasZU", "true",
"Support zero-upper SETcc/IMUL">;
+def FeatureJMPABS : SubtargetFeature<"jmpabs", "HasJMPABS", "true",
+ "Support 64-bit absolute JMP">;
def FeatureUseGPR32InInlineAsm
: SubtargetFeature<"inline-asm-use-gpr32", "UseInlineAsmGPR32", "true",
"Enable use of GPR32 in inline assembly for APX">;
@@ -1188,6 +1190,7 @@ def ProcessorFeatures {
FeaturePPX,
FeatureNDD,
FeatureNF,
+ FeatureJMPABS,
FeatureMOVRS,
FeatureAMXMOVRS,
FeatureAMXAVX512,
@@ -1361,6 +1364,7 @@ def ProcessorFeatures {
FeatureNF,
FeatureNDD,
FeatureZU,
+ FeatureJMPABS,
FeatureCCMP,
FeaturePREFETCHI];
list<SubtargetFeature> NVLFeatures =
diff --git a/llvm/lib/Target/X86/X86InstrCompiler.td b/llvm/lib/Target/X86/X86InstrCompiler.td
index 65188c0295f8c..04fb7ba01edf9 100644
--- a/llvm/lib/Target/X86/X86InstrCompiler.td
+++ b/llvm/lib/Target/X86/X86InstrCompiler.td
@@ -1426,6 +1426,14 @@ def : Pat<(X86tcret (i64 texternalsym:$dst), timm:$off),
(TCRETURNdi64 texternalsym:$dst, timm:$off)>,
Requires<[IsLP64]>;
+def : Pat<(X86tcret (i64 (X86Wrapper tglobaladdr:$dst)), timm:$off),
+ (TCRETURNdi64 tglobaladdr:$dst, timm:$off)>,
+ Requires<[IsNotPIC, HasJMPABS]>;
+
+def : Pat<(X86tcret (i64 (X86Wrapper texternalsym:$dst)), timm:$off),
+ (TCRETURNdi64 texternalsym:$dst, timm:$off)>,
+ Requires<[IsNotPIC, HasJMPABS]>;
+
// Normal calls, with various flavors of addresses.
def : Pat<(X86call (i32 tglobaladdr:$dst)),
(CALLpcrel32 tglobaladdr:$dst)>;
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index 21e6bacbacee2..caa5880532760 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -51,6 +51,7 @@ def PreferLegacySetCC : Predicate<"!Subtarget->hasZU() || "
def PreferNoLegacySetCC : Predicate<"Subtarget->hasZU() && "
"!Subtarget->preferLegacySetCC()">;
def HasCF : Predicate<"Subtarget->hasCF()">;
+def HasJMPABS : Predicate<"Subtarget->hasJMPABS()">;
def HasCMOV : Predicate<"Subtarget->canUseCMOV()">;
def NoCMOV : Predicate<"!Subtarget->canUseCMOV()">;
def HasNOPL : Predicate<"Subtarget->hasNOPL()">;
diff --git a/llvm/lib/Target/X86/X86MCInstLower.cpp b/llvm/lib/Target/X86/X86MCInstLower.cpp
index 0d4131632ff56..6740a3e38eb6c 100644
--- a/llvm/lib/Target/X86/X86MCInstLower.cpp
+++ b/llvm/lib/Target/X86/X86MCInstLower.cpp
@@ -370,7 +370,7 @@ MCOperand X86MCInstLower::LowerMachineOperand(const MachineInstr *MI,
// Replace TAILJMP opcodes with their equivalent opcodes that have encoding
// information.
-static unsigned convertTailJumpOpcode(unsigned Opcode) {
+static unsigned convertTailJumpOpcode(unsigned Opcode, bool IsLarge = false) {
switch (Opcode) {
case X86::TAILJMPr:
Opcode = X86::JMP32r;
@@ -392,7 +392,7 @@ static unsigned convertTailJumpOpcode(unsigned Opcode) {
break;
case X86::TAILJMPd:
case X86::TAILJMPd64:
- Opcode = X86::JMP_1;
+ Opcode = IsLarge ? X86::JMPABS64i : X86::JMP_1;
break;
case X86::TAILJMPd_CC:
case X86::TAILJMPd64_CC:
@@ -485,10 +485,18 @@ void X86MCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
case X86::TAILJMPr64:
case X86::TAILJMPr64_REX:
case X86::TAILJMPd:
- case X86::TAILJMPd64:
assert(OutMI.getNumOperands() == 1 && "Unexpected number of operands!");
OutMI.setOpcode(convertTailJumpOpcode(OutMI.getOpcode()));
break;
+ case X86::TAILJMPd64: {
+ assert(OutMI.getNumOperands() == 1 && "Unexpected number of operands!");
+ bool IsLarge = TM.getCodeModel() == CodeModel::Large;
+ assert((!IsLarge || AsmPrinter.getSubtarget().hasJMPABS()) &&
+ "Unexpected TAILJMPd64 in large code model without JMPABS");
+ OutMI.setOpcode(convertTailJumpOpcode(
+ OutMI.getOpcode(), TM.getCodeModel() == CodeModel::Large));
+ break;
+ }
case X86::TAILJMPd_CC:
case X86::TAILJMPd64_CC:
assert(OutMI.getNumOperands() == 2 && "Unexpected number of operands!");
diff --git a/llvm/lib/Target/X86/X86Subtarget.cpp b/llvm/lib/Target/X86/X86Subtarget.cpp
index 4e2e98410f325..a36fd214e33f5 100644
--- a/llvm/lib/Target/X86/X86Subtarget.cpp
+++ b/llvm/lib/Target/X86/X86Subtarget.cpp
@@ -264,8 +264,9 @@ void X86Subtarget::initSubtargetFeatures(StringRef CPU, StringRef TuneCPU,
FullFS = (Twine(FullFS) + "," + FS).str();
// Disable 64-bit only features in non-64-bit mode.
- StringRef FeaturesIn64BitOnly[] = {
- "egpr", "push2pop2", "ppx", "ndd", "ccmp", "nf", "cf", "zu", "uintr"};
+ StringRef FeaturesIn64BitOnly[] = {"egpr", "push2pop2", "ppx", "ndd",
+ "ccmp", "nf", "cf", "zu",
+ "jmpabs", "uintr"};
if (FullFS.find("-64bit-mode") != std::string::npos)
for (StringRef F : FeaturesIn64BitOnly)
FullFS += ",-" + F.str();
diff --git a/llvm/lib/TargetParser/Host.cpp b/llvm/lib/TargetParser/Host.cpp
index e1bdfbe42d07f..dfe97f178bd46 100644
--- a/llvm/lib/TargetParser/Host.cpp
+++ b/llvm/lib/TargetParser/Host.cpp
@@ -2184,6 +2184,7 @@ StringMap<bool> sys::getHostCPUFeatures() {
Features["nf"] = HasAPXF;
Features["cf"] = HasAPXF;
Features["zu"] = HasAPXF;
+ Features["jmpabs"] = HasAPXF;
bool HasLeafD = MaxLevel >= 0xd &&
!getX86CpuIDAndInfoEx(0xd, 0x1, &EAX, &EBX, &ECX, &EDX);
diff --git a/llvm/lib/TargetParser/X86TargetParser.cpp b/llvm/lib/TargetParser/X86TargetParser.cpp
index f848b1ac08607..b3859eb4ff2fd 100644
--- a/llvm/lib/TargetParser/X86TargetParser.cpp
+++ b/llvm/lib/TargetParser/X86TargetParser.cpp
@@ -142,8 +142,8 @@ constexpr FeatureBitset FeaturesDiamondRapids =
FeatureCMPCCXADD | FeatureAVXIFMA | FeatureAVXNECONVERT |
FeatureAVXVNNIINT8 | FeatureAVXVNNIINT16 | FeatureSHA512 | FeatureSM3 |
FeatureSM4 | FeatureEGPR | FeatureZU | FeatureCCMP | FeaturePush2Pop2 |
- FeaturePPX | FeatureNDD | FeatureNF | FeatureMOVRS | FeatureAMX_MOVRS |
- FeatureAMX_AVX512 | FeatureAMX_FP8 | FeatureAMX_TF32;
+ FeaturePPX | FeatureNDD | FeatureNF | FeatureJMPABS | FeatureMOVRS |
+ FeatureAMX_MOVRS | FeatureAMX_AVX512 | FeatureAMX_FP8 | FeatureAMX_TF32;
// Intel Atom processors.
// Bonnell has feature parity with Core2 and adds MOVBE.
@@ -178,7 +178,7 @@ constexpr FeatureBitset FeaturesPantherlake =
constexpr FeatureBitset FeaturesNovalake =
FeaturesPantherlake | FeaturePREFETCHI | FeatureAVX10_2 | FeatureMOVRS |
FeatureEGPR | FeatureZU | FeatureCCMP | FeaturePush2Pop2 | FeaturePPX |
- FeatureNDD | FeatureNF;
+ FeatureNDD | FeatureNF | FeatureJMPABS;
constexpr FeatureBitset FeaturesClearwaterforest =
(FeaturesSierraforest ^ FeatureWIDEKL) | FeatureAVXVNNIINT16 |
FeatureSHA512 | FeatureSM3 | FeatureSM4 | FeaturePREFETCHI | FeatureUSERMSR;
@@ -659,11 +659,12 @@ constexpr FeatureBitset ImpliedFeaturesCCMP = {};
constexpr FeatureBitset ImpliedFeaturesNF = {};
constexpr FeatureBitset ImpliedFeaturesCF = {};
constexpr FeatureBitset ImpliedFeaturesZU = {};
+constexpr FeatureBitset ImpliedFeaturesJMPABS = {};
constexpr FeatureBitset ImpliedFeaturesAPXF =
ImpliedFeaturesEGPR | ImpliedFeaturesPush2Pop2 | ImpliedFeaturesPPX |
ImpliedFeaturesNDD | ImpliedFeaturesCCMP | ImpliedFeaturesNF |
- ImpliedFeaturesCF | ImpliedFeaturesZU;
+ ImpliedFeaturesCF | ImpliedFeaturesZU | ImpliedFeaturesJMPABS;
constexpr FeatureBitset ImpliedFeaturesMOVRS = {};
diff --git a/llvm/test/CodeGen/X86/tailcc-largecode.ll b/llvm/test/CodeGen/X86/tailcc-largecode.ll
index ac32f67fce9e6..cdc39f01522a2 100644
--- a/llvm/test/CodeGen/X86/tailcc-largecode.ll
+++ b/llvm/test/CodeGen/X86/tailcc-largecode.ll
@@ -1,12 +1,15 @@
-; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false | FileCheck %s
+; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false | FileCheck %s --check-prefixes=CHECK,JMP
+; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false -mattr=jmpabs | FileCheck %s --check-prefixes=CHECK,JMPABS
declare tailcc i32 @callee(i32 %arg)
define tailcc i32 @directcall(i32 %arg) {
entry:
; This is the large code model, so &callee may not fit into the jmp
; instruction. Instead, stick it into a register.
-; CHECK: movabsq $callee, [[REGISTER:%r[a-z0-9]+]]
-; CHECK: jmpq *[[REGISTER]] # TAILCALL
+; JMP: movabsq $callee, [[REGISTER:%r[a-z0-9]+]]
+; JMP: jmpq *[[REGISTER]] # TAILCALL
+; JMPABS-NOT: movabsq
+; JMPABS: jmpabs $callee # TAILCALL
%res = tail call tailcc i32 @callee(i32 %arg)
ret i32 %res
}
@@ -53,7 +56,8 @@ define tailcc i32 @direct_manyargs() {
; the jmp instruction. Put it into a register which won't be clobbered
; while restoring callee-saved registers and won't be used for passing
; arguments.
-; CHECK: movabsq $manyargs_callee, %rax
+; JMP: movabsq $manyargs_callee, %rax
+; JMPABS-NOT: movabsq
; Pass the register arguments, in the right registers.
; CHECK: movl $1, %edi
; CHECK: movl $2, %esi
@@ -64,7 +68,8 @@ define tailcc i32 @direct_manyargs() {
; Adjust the stack to "return".
; CHECK: popq
; And tail-call to the target.
-; CHECK: jmpq *%rax # TAILCALL
+; JMP: jmpq *%rax # TAILCALL
+; JMPABS: jmpabs $manyargs_callee # TAILCALL
%res = tail call tailcc i32 @manyargs_callee(i32 1, i32 2, i32 3, i32 4,
i32 5, i32 6, i32 7)
ret i32 %res
>From 9b920015e7f1b600be05c3593b849f887eb64a36 Mon Sep 17 00:00:00 2001
From: Phoebe Wang <phoebe.wang at intel.com>
Date: Mon, 16 Mar 2026 14:07:38 +0800
Subject: [PATCH 2/2] Add tests for PIC + large code model
---
llvm/test/CodeGen/X86/tailcc-largecode.ll | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/llvm/test/CodeGen/X86/tailcc-largecode.ll b/llvm/test/CodeGen/X86/tailcc-largecode.ll
index cdc39f01522a2..a3762ce81030f 100644
--- a/llvm/test/CodeGen/X86/tailcc-largecode.ll
+++ b/llvm/test/CodeGen/X86/tailcc-largecode.ll
@@ -1,5 +1,7 @@
; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false | FileCheck %s --check-prefixes=CHECK,JMP
; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false -mattr=jmpabs | FileCheck %s --check-prefixes=CHECK,JMPABS
+; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false -relocation-model=pic | FileCheck %s --check-prefixes=CHECK,PIC
+; RUN: llc < %s -mtriple=x86_64-linux-gnu -code-model=large -enable-misched=false -mattr=jmpabs -relocation-model=pic | FileCheck %s --check-prefixes=CHECK,PIC
declare tailcc i32 @callee(i32 %arg)
define tailcc i32 @directcall(i32 %arg) {
@@ -10,6 +12,9 @@ entry:
; JMP: jmpq *[[REGISTER]] # TAILCALL
; JMPABS-NOT: movabsq
; JMPABS: jmpabs $callee # TAILCALL
+; PIC: movabsq $_GLOBAL_OFFSET_TABLE_
+; PIC: movabsq $callee at GOT
+; PIC: jmpq *
%res = tail call tailcc i32 @callee(i32 %arg)
ret i32 %res
}
@@ -51,6 +56,7 @@ define tailcc i32 @direct_manyargs() {
; the stack argument and the return adjustment will change too.)
; CHECK: pushq
; Pass the stack argument.
+; PIC: movabsq $_GLOBAL_OFFSET_TABLE
; CHECK: movl $7, 16(%rsp)
; This is the large code model, so &manyargs_callee may not fit into
; the jmp instruction. Put it into a register which won't be clobbered
@@ -58,6 +64,7 @@ define tailcc i32 @direct_manyargs() {
; arguments.
; JMP: movabsq $manyargs_callee, %rax
; JMPABS-NOT: movabsq
+; PIC: movabsq $manyargs_callee at GOT
; Pass the register arguments, in the right registers.
; CHECK: movl $1, %edi
; CHECK: movl $2, %esi
@@ -70,6 +77,7 @@ define tailcc i32 @direct_manyargs() {
; And tail-call to the target.
; JMP: jmpq *%rax # TAILCALL
; JMPABS: jmpabs $manyargs_callee # TAILCALL
+; PIC: jmpq *
%res = tail call tailcc i32 @manyargs_callee(i32 1, i32 2, i32 3, i32 4,
i32 5, i32 6, i32 7)
ret i32 %res
More information about the cfe-commits
mailing list