[llvm] [M68k] implement -mxgot (PR #119803)
John Paul Adrian Glaubitz via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 10 00:35:56 PST 2026
glaubitz wrote:
The following very rough patch fixes it for me. It was generated with the help of Google Gemini AI. It should not be merged as is, of course. But it should give us an idea what changes are necessary to fix this bug.
```diff
diff --git a/llvm/lib/Target/M68k/M68k.td b/llvm/lib/Target/M68k/M68k.td
index dfa44a423a..cafae7e42e 100644
--- a/llvm/lib/Target/M68k/M68k.td
+++ b/llvm/lib/Target/M68k/M68k.td
@@ -65,6 +65,12 @@ foreach i = {0-7} in
SubtargetFeature<"reserve-d"#i, "UserReservedRegister[M68k::D"#i#"]",
"true", "Reserve D"#i#" register">;
+def FeatureXGOT
+ : SubtargetFeature<"xgot", "UseXGOT", "true", "Assume 32-bit GOT">;
+
+def IsNotXGOT : Predicate<"!Subtarget->useXGOT()">;
+def IsXGOT : Predicate<"Subtarget->useXGOT()">;
+
//===----------------------------------------------------------------------===//
// M68k processors supported.
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
index 9c3d61ec60..be5fd42e3c 100644
--- a/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
+++ b/llvm/lib/Target/M68k/M68kISelDAGToDAG.cpp
@@ -680,6 +680,36 @@ void M68kDAGToDAGISel::Select(SDNode *Node) {
break;
case ISD::GLOBAL_OFFSET_TABLE: {
+ // --- XGOT PATCH START ---
+ // Access the subtarget to check for the XGOT feature
+ const M68kSubtarget &Subtarget = CurDAG->getSubtarget<M68kSubtarget>();
+
+ if (Subtarget.useXGOT()) {
+ // We cannot use LEA32q because it forces a 16-bit relocation.
+ // We must manually select the 32-bit sequence:
+ // 1. Move 32-bit offset into Data Register: move.l #_GLOBAL_OFFSET_TABLE_ at GOTPCREL, %d0
+ SDValue GOTSym = CurDAG->getTargetExternalSymbol(
+ "_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
+
+ SDNode *Offset = CurDAG->getMachineNode(
+ M68k::MOV32ri, DL, MVT::i32, GOTSym);
+
+ // 2. Load PC into Address Register: lea (0, %pc), %a0
+ SDValue Zero = CurDAG->getTargetConstant(0, DL, MVT::i32);
+ SDNode *PC = CurDAG->getMachineNode(
+ M68k::LEA32q, DL, MVT::i32, Zero);
+
+ // 3. Add Offset to PC: add.l %d0, %a0
+ // Input order for ADD32ar is typically (Base, Offset) or (Dest, Source)
+ MachineSDNode *Res = CurDAG->getMachineNode(
+ M68k::ADD32ar, DL, MVT::i32, SDValue(PC, 0), SDValue(Offset, 0));
+
+ ReplaceNode(Node, Res);
+ return;
+ }
+ // --- XGOT PATCH END ---
+
+ // Original 16-bit Fallback
SDValue GOT = CurDAG->getTargetExternalSymbol(
"_GLOBAL_OFFSET_TABLE_", MVT::i32, M68kII::MO_GOTPCREL);
MachineSDNode *Res =
diff --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp
index 65084087f6..a3be875825 100644
--- a/llvm/lib/Target/M68k/M68kISelLowering.cpp
+++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp
@@ -144,6 +144,7 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM,
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
+ setOperationAction(ISD::ExternalSymbol, MVT::i32, Custom);
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
setOperationAction(ISD::ExternalSymbol, MVT::i32, Custom);
setOperationAction(ISD::BlockAddress, MVT::i32, Custom);
@@ -778,28 +779,27 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
InGlue = Chain.getValue(1);
}
+ // --- XGOT PATCH: Handle Call Flags ---
if (Callee->getOpcode() == ISD::GlobalAddress) {
- // If the callee is a GlobalAddress node (quite common, every direct call
- // is) turn it into a TargetGlobalAddress node so that legalize doesn't hack
- // it.
GlobalAddressSDNode *G = cast<GlobalAddressSDNode>(Callee);
-
- // We should use extra load for direct calls to dllimported functions in
- // non-JIT mode.
const GlobalValue *GV = G->getGlobal();
if (!GV->hasDLLImportStorageClass()) {
unsigned char OpFlags = Subtarget.classifyGlobalFunctionReference(GV);
+ // FIX: If XGOT is enabled, force absolute addressing (0).
+ // This prevents MO_PCREL flags, which would trigger 16-bit BSR instructions.
+ // Instead, we get a 32-bit JSR.
+ if (Subtarget.useXGOT()) {
+ OpFlags = 0;
+ }
+
Callee = DAG.getTargetGlobalAddress(
GV, DL, getPointerTy(DAG.getDataLayout()), G->getOffset(), OpFlags);
+ // Only perform indirect GOT call if flags allow it (and XGOT didn't clear them)
if (OpFlags == M68kII::MO_GOTPCREL) {
-
- // Add a wrapper.
Callee = DAG.getNode(M68kISD::WrapperPC, DL,
getPointerTy(DAG.getDataLayout()), Callee);
-
- // Add extra indirection
Callee = DAG.getLoad(
getPointerTy(DAG.getDataLayout()), DL, DAG.getEntryNode(), Callee,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
@@ -810,9 +810,15 @@ SDValue M68kTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
unsigned char OpFlags =
Subtarget.classifyGlobalFunctionReference(nullptr, *Mod);
+ // FIX: Force absolute addressing for XGOT on external symbols too.
+ if (Subtarget.useXGOT()) {
+ OpFlags = 0;
+ }
+
Callee = DAG.getTargetExternalSymbol(
S->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlags);
}
+ // --- END XGOT PATCH ---
SmallVector<SDValue, 8> Ops;
@@ -2650,7 +2656,37 @@ SDValue M68kTargetLowering::LowerADDC_ADDE_SUBC_SUBE(SDValue Op,
SDValue M68kTargetLowering::LowerConstantPool(SDValue Op,
SelectionDAG &DAG) const {
ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
+ MVT PtrVT = getPointerTy(DAG.getDataLayout());
+ SDLoc DL(CP);
+ // --- XGOT PATCH START ---
+ // Fix for .rodata (string literals/floats) causing R_68K_PC16 overflows.
+ // If XGOT is active in PIC mode, we must use 32-bit offsets.
+ if (DAG.getTarget().getRelocationModel() != llvm::Reloc::Static &&
+ Subtarget.useXGOT()) {
+
+ // 1. Create TargetConstantPool with GOTPCREL flag.
+ // We reuse this flag because your MCCodeEmitter patch specifically intercepts
+ // it to generate a 32-bit FK_Data_4 relocation.
+ SDValue Result = DAG.getTargetConstantPool(
+ CP->getConstVal(), PtrVT, CP->getAlign(), CP->getOffset(), M68kII::MO_GOTPCREL);
+
+ // 2. Load the 32-bit offset into a data register:
+ // move.l #Const at GOTPCREL, %d0
+ Result = SDValue(DAG.getMachineNode(M68k::MOV32ri, DL, PtrVT, Result), 0);
+
+ // 3. Add the GOT Base (%a5) to the offset:
+ // add.l %a5, %d0
+ // This calculates the absolute address of the constant without using %pc.
+ Result = DAG.getNode(ISD::ADD, DL, PtrVT,
+ DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT),
+ Result);
+
+ return Result;
+ }
+ // --- XGOT PATCH END ---
+
+ // --- Original Implementation Below ---
// In PIC mode (unless we're in PCRel PIC mode) we add an offset to the
// global base reg.
unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr);
@@ -2660,11 +2696,11 @@ SDValue M68kTargetLowering::LowerConstantPool(SDValue Op,
WrapperKind = M68kISD::WrapperPC;
}
- MVT PtrVT = getPointerTy(DAG.getDataLayout());
+ // Note: PtrVT is already defined above in the XGOT patch block.
SDValue Result = DAG.getTargetConstantPool(
CP->getConstVal(), PtrVT, CP->getAlign(), CP->getOffset(), OpFlag);
- SDLoc DL(CP);
+ // SDLoc DL(CP); // Already defined above
Result = DAG.getNode(WrapperKind, DL, PtrVT, Result);
// With PIC, the address is actually $g + Offset.
@@ -2679,33 +2715,57 @@ SDValue M68kTargetLowering::LowerConstantPool(SDValue Op,
SDValue M68kTargetLowering::LowerExternalSymbol(SDValue Op,
SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ auto PtrVT = getPointerTy(DAG.getDataLayout());
const char *Sym = cast<ExternalSymbolSDNode>(Op)->getSymbol();
- // In PIC mode (unless we're in PCRel PIC mode) we add an offset to the
- // global base reg.
+ // --- FIX 1: Short-circuit GOT base ---
+ if (Sym && StringRef(Sym) == "_GLOBAL_OFFSET_TABLE_") {
+ return DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT);
+ }
+
const Module *Mod = DAG.getMachineFunction().getFunction().getParent();
unsigned char OpFlag = Subtarget.classifyExternalReference(*Mod);
+ // --- FIX 2: Handle XGOT for External Symbols ---
+ // If XGOT is on, avoid 16-bit wrappers.
+ if (DAG.getTarget().getRelocationModel() != llvm::Reloc::Static &&
+ Subtarget.useXGOT()) {
+
+ // Create TargetExternalSymbol with GOTPCREL flag
+ SDValue Result = DAG.getTargetExternalSymbol(Sym, PtrVT, M68kII::MO_GOTPCREL);
+
+ // 1. Move 32-bit offset: move.l #Sym at GOTPCREL, %d0
+ Result = SDValue(DAG.getMachineNode(M68k::MOV32ri, DL, PtrVT, Result), 0);
+
+ // 2. Add GOT Base: add.l %a5, %d0
+ Result = DAG.getNode(ISD::ADD, DL, PtrVT,
+ DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT),
+ Result);
+
+ // 3. Load from GOT if needed (almost always yes for external symbols)
+ if (M68kII::isGlobalStubReference(OpFlag)) {
+ Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result,
+ MachinePointerInfo::getGOT(DAG.getMachineFunction()));
+ }
+ return Result;
+ }
+
+ // --- Fallback (Original Logic) ---
unsigned WrapperKind = M68kISD::Wrapper;
if (M68kII::isPCRelGlobalReference(OpFlag)) {
WrapperKind = M68kISD::WrapperPC;
}
- auto PtrVT = getPointerTy(DAG.getDataLayout());
SDValue Result = DAG.getTargetExternalSymbol(Sym, PtrVT, OpFlag);
-
- SDLoc DL(Op);
Result = DAG.getNode(WrapperKind, DL, PtrVT, Result);
- // With PIC, the address is actually $g + Offset.
if (M68kII::isGlobalRelativeToPICBase(OpFlag)) {
Result = DAG.getNode(ISD::ADD, DL, PtrVT,
- DAG.getNode(M68kISD::GLOBAL_BASE_REG, SDLoc(), PtrVT),
+ DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT),
Result);
}
- // For symbols that require a load from a stub to get the address, emit the
- // load.
if (M68kII::isGlobalStubReference(OpFlag)) {
Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
@@ -2716,6 +2776,32 @@ SDValue M68kTargetLowering::LowerExternalSymbol(SDValue Op,
SDValue M68kTargetLowering::LowerBlockAddress(SDValue Op,
SelectionDAG &DAG) const {
+ // --- XGOT PATCH START ---
+ // Fix for Block Addresses (Computed Gotos) causing R_68K_PC16 overflows.
+ if (DAG.getTarget().getRelocationModel() != llvm::Reloc::Static &&
+ Subtarget.useXGOT()) {
+ const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
+ int64_t Offset = cast<BlockAddressSDNode>(Op)->getOffset();
+ SDLoc DL(Op);
+ auto PtrVT = getPointerTy(DAG.getDataLayout());
+
+ // 1. Create TargetBlockAddress with GOTPCREL flag.
+ // We intentionally ignore the existing OpFlags classification here.
+ SDValue Result = DAG.getTargetBlockAddress(
+ BA, PtrVT, Offset, M68kII::MO_GOTPCREL);
+
+ // 2. Load the 32-bit offset: move.l #Label at GOTPCREL, %d0
+ Result = SDValue(DAG.getMachineNode(M68k::MOV32ri, DL, PtrVT, Result), 0);
+
+ // 3. Add the GOT Base (%a5): add.l %a5, %d0
+ Result = DAG.getNode(ISD::ADD, DL, PtrVT,
+ DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT),
+ Result);
+ return Result;
+ }
+ // --- XGOT PATCH END ---
+
+ // --- Original Implementation ---
unsigned char OpFlags = Subtarget.classifyBlockAddressReference();
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
int64_t Offset = cast<BlockAddressSDNode>(Op)->getOffset();
@@ -2744,11 +2830,47 @@ SDValue M68kTargetLowering::LowerBlockAddress(SDValue Op,
SDValue M68kTargetLowering::LowerGlobalAddress(const GlobalValue *GV,
const SDLoc &DL, int64_t Offset,
SelectionDAG &DAG) const {
- unsigned char OpFlags = Subtarget.classifyGlobalReference(GV);
auto PtrVT = getPointerTy(DAG.getDataLayout());
- // Create the TargetGlobalAddress node, folding in the constant
- // offset if it is legal.
+ // --- FIX 1: Special Case for _GLOBAL_OFFSET_TABLE_ ---
+ if (GV->getName() == "_GLOBAL_OFFSET_TABLE_") {
+ return DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT);
+ }
+
+ // --- FIX 2: Force 32-bit XGOT for EVERYTHING in PIC mode ---
+ // If XGOT is enabled and we are generating PIC, we cannot use 16-bit
+ // PC-relative addressing for anything, not even local strings (.rodata).
+ if (DAG.getTarget().getRelocationModel() != llvm::Reloc::Static &&
+ Subtarget.useXGOT()) {
+
+ // 1. Create TargetGlobalAddress with GOTPCREL flag
+ // We intentionally force MO_GOTPCREL to get the 32-bit offset.
+ SDValue GA = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Offset, M68kII::MO_GOTPCREL);
+
+ // 2. Get the Global Base Reg (%a5)
+ SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT);
+
+ // 3. Load the 32-bit offset: move.l #Symbol at GOTPCREL, %d0
+ SDValue GOffset = SDValue(DAG.getMachineNode(M68k::MOV32ri, DL, PtrVT, GA), 0);
+
+ // 4. Add the GOT base: add.l %a5, %d0
+ SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, GOT, GOffset);
+
+ // 5. Handle Indirect (GOT slot) vs Direct (Local Offset)
+ unsigned char OpFlags = Subtarget.classifyGlobalReference(GV);
+
+ // If it is a global stub (shared lib), we must load the address FROM the GOT.
+ if (M68kII::isGlobalStubReference(OpFlags)) {
+ return DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Ptr, MachinePointerInfo());
+ }
+
+ // If it is local (like .rodata), 'Ptr' is already the address we want.
+ // (GOT_Base + Offset_to_Symbol). The 'Offset' param is already folded into GA.
+ return Ptr;
+ }
+
+ // --- Fallback to Original Logic (for !XGOT) ---
+ unsigned char OpFlags = Subtarget.classifyGlobalReference(GV);
SDValue Result;
if (M68kII::isDirectGlobalReference(OpFlags)) {
Result = DAG.getTargetGlobalAddress(GV, DL, PtrVT, Offset);
@@ -2762,22 +2884,17 @@ SDValue M68kTargetLowering::LowerGlobalAddress(const GlobalValue *GV,
else
Result = DAG.getNode(M68kISD::Wrapper, DL, PtrVT, Result);
- // With PIC, the address is actually $g + Offset.
if (M68kII::isGlobalRelativeToPICBase(OpFlags)) {
Result =
DAG.getNode(ISD::ADD, DL, PtrVT,
DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT), Result);
}
- // For globals that require a load from a stub to get the address, emit the
- // load.
if (M68kII::isGlobalStubReference(OpFlags)) {
Result = DAG.getLoad(PtrVT, DL, DAG.getEntryNode(), Result,
MachinePointerInfo::getGOT(DAG.getMachineFunction()));
}
- // If there was a non-zero offset that we didn't fold, create an explicit
- // addition for it.
if (Offset != 0) {
Result = DAG.getNode(ISD::ADD, DL, PtrVT, Result,
DAG.getConstant(Offset, DL, PtrVT));
@@ -2801,6 +2918,30 @@ SDValue M68kTargetLowering::LowerJumpTable(SDValue Op,
SelectionDAG &DAG) const {
JumpTableSDNode *JT = cast<JumpTableSDNode>(Op);
+ // --- XGOT PATCH START ---
+ // Fix for Jump Tables (Switch/Match) causing R_68K_PC16 overflows.
+ if (DAG.getTarget().getRelocationModel() != llvm::Reloc::Static &&
+ Subtarget.useXGOT()) {
+ auto PtrVT = getPointerTy(DAG.getDataLayout());
+ SDLoc DL(JT);
+
+ // 1. Create TargetJumpTable with GOTPCREL flag.
+ // This forces the backend to use the 32-bit offset we implemented.
+ SDValue Result = DAG.getTargetJumpTable(
+ JT->getIndex(), PtrVT, M68kII::MO_GOTPCREL);
+
+ // 2. Load the 32-bit offset: move.l #.LJTI... at GOTPCREL, %d0
+ Result = SDValue(DAG.getMachineNode(M68k::MOV32ri, DL, PtrVT, Result), 0);
+
+ // 3. Add the GOT Base (%a5): add.l %a5, %d0
+ Result = DAG.getNode(ISD::ADD, DL, PtrVT,
+ DAG.getNode(M68kISD::GLOBAL_BASE_REG, DL, PtrVT),
+ Result);
+ return Result;
+ }
+ // --- XGOT PATCH END ---
+
+ // --- Original Implementation ---
// In PIC mode (unless we're in PCRel PIC mode) we add an offset to the
// global base reg.
unsigned char OpFlag = Subtarget.classifyLocalReference(nullptr);
diff --git a/llvm/lib/Target/M68k/M68kInstrCompiler.td b/llvm/lib/Target/M68k/M68kInstrCompiler.td
index 2ecf5ca0e6..79d48fe1e6 100644
--- a/llvm/lib/Target/M68k/M68kInstrCompiler.td
+++ b/llvm/lib/Target/M68k/M68kInstrCompiler.td
@@ -41,8 +41,8 @@ def : Pat<(store (i32 (MxWrapper tblockaddress:$src)), iPTR:$dst),
(MOV32ji MxARI32:$dst, tblockaddress:$src)>;
def : Pat<(i32 (MxWrapperPC tconstpool :$src)), (LEA32q tconstpool :$src)>;
-def : Pat<(i32 (MxWrapperPC tglobaladdr :$src)), (LEA32q tglobaladdr :$src)>;
-def : Pat<(i32 (MxWrapperPC texternalsym :$src)), (LEA32q texternalsym :$src)>;
+def : Pat<(i32 (MxWrapperPC tglobaladdr :$src)), (LEA32q tglobaladdr :$src)>, Requires<[IsNotXGOT]>;
+def : Pat<(i32 (MxWrapperPC texternalsym :$src)), (LEA32q texternalsym :$src)>, Requires<[IsNotXGOT]>;
def : Pat<(i32 (MxWrapperPC tjumptable :$src)), (LEA32q tjumptable :$src)>;
def : Pat<(i32 (MxWrapperPC tblockaddress :$src)), (LEA32q tblockaddress :$src)>;
diff --git a/llvm/lib/Target/M68k/M68kInstrControl.td b/llvm/lib/Target/M68k/M68kInstrControl.td
index 4e94b2ed3a..a1b4f60fe0 100644
--- a/llvm/lib/Target/M68k/M68kInstrControl.td
+++ b/llvm/lib/Target/M68k/M68kInstrControl.td
@@ -304,9 +304,24 @@ multiclass CallPat<MxCall callOp, Predicate pred> {
}
}
+// --- Patch: Handle 32-bit Calls for XGOT ---
+
+// 1. Standard PIC (Small Code Model): Use 16-bit PC-relative calls (CALLq).
+// We restrict this to !XGOT so it doesn't trigger for large binaries.
+let Predicates = [IsNotXGOT] in
defm : CallPat<CALLq, IsPIC>;
+
+// 2. Large PIC (XGOT): Use 32-bit Absolute calls (CALLb).
+// CALLb expands to JSR (Jump to Subroutine), which supports 32-bit offsets.
+// This prevents R_68K_PC16 overflows in large libraries like libstd.
+let Predicates = [IsXGOT] in
+defm : CallPat<CALLb, IsPIC>;
+
+// 3. Non-PIC (Static): Keep using CALLb as before.
defm : CallPat<CALLb, IsNotPIC>;
+// -------------------------------------------
+
def : Pat<(MxCall iPTR:$dst), (CALLj MxARI32:$dst)>;
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/M68k/M68kInstrInfo.cpp b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
index 3a9f88269f..cab59e6018 100644
--- a/llvm/lib/Target/M68k/M68kInstrInfo.cpp
+++ b/llvm/lib/Target/M68k/M68kInstrInfo.cpp
@@ -916,6 +916,7 @@ struct M68kGlobalBaseReg : public MachineFunctionPass {
bool runOnMachineFunction(MachineFunction &MF) override {
const M68kSubtarget &STI = MF.getSubtarget<M68kSubtarget>();
M68kMachineFunctionInfo *MxFI = MF.getInfo<M68kMachineFunctionInfo>();
+ MachineRegisterInfo &RegInfo = MF.getRegInfo();
unsigned GlobalBaseReg = MxFI->getGlobalBaseReg();
@@ -929,9 +930,25 @@ struct M68kGlobalBaseReg : public MachineFunctionPass {
DebugLoc DL = FirstMBB.findDebugLoc(MBBI);
const M68kInstrInfo *TII = STI.getInstrInfo();
- // Generate lea (__GLOBAL_OFFSET_TABLE_,%PC), %A5
- BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::LEA32q), GlobalBaseReg)
- .addExternalSymbol("_GLOBAL_OFFSET_TABLE_", M68kII::MO_GOTPCREL);
+ if (STI.useXGOT()) {
+ // XGOT Sequence:
+ // move.l #_GLOBAL_OFFSET_TABLE_ at GOTPCREL, %d0
+ // lea (0, %pc), %a0
+ // add.l %d0, %a0 -> GlobalBaseReg
+ Register OffsetReg = RegInfo.createVirtualRegister(&M68k::DR32RegClass);
+ Register PCReg = RegInfo.createVirtualRegister(&M68k::AR32_NOSPRegClass);
+
+ BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::MOV32ri), OffsetReg)
+ .addExternalSymbol("_GLOBAL_OFFSET_TABLE_", M68kII::MO_GOTPCREL);
+ BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::LEA32q), PCReg).addImm(0);
+ BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::ADD32ar), GlobalBaseReg)
+ .addReg(PCReg)
+ .addReg(OffsetReg);
+ } else {
+ // Generate lea (__GLOBAL_OFFSET_TABLE_,%PC), %A5
+ BuildMI(FirstMBB, MBBI, DL, TII->get(M68k::LEA32q), GlobalBaseReg)
+ .addExternalSymbol("_GLOBAL_OFFSET_TABLE_", M68kII::MO_GOTPCREL);
+ }
return true;
}
diff --git a/llvm/lib/Target/M68k/M68kSubtarget.h b/llvm/lib/Target/M68k/M68kSubtarget.h
index 4f9685814d..066d04ac0f 100644
--- a/llvm/lib/Target/M68k/M68kSubtarget.h
+++ b/llvm/lib/Target/M68k/M68kSubtarget.h
@@ -48,6 +48,8 @@ protected:
enum SubtargetEnum { M00, M10, M20, M30, M40, M60 };
SubtargetEnum SubtargetKind = M00;
+ bool UseXGOT = false;
+
enum FPKindEnum { M881, M882 };
std::optional<FPKindEnum> FPUKind;
@@ -78,6 +80,8 @@ public:
~M68kSubtarget() override;
+ bool useXGOT() const { return UseXGOT; }
+
/// Parses features string setting specified subtarget options. Definition
/// of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);
diff --git a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
index 9b755e021c..c2bb6f81a4 100644
--- a/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
+++ b/llvm/lib/Target/M68k/MCTargetDesc/M68kMCCodeEmitter.cpp
@@ -24,6 +24,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/raw_ostream.h"
@@ -134,16 +135,24 @@ void M68kMCCodeEmitter::encodeRelocImm(const MCInst &MI, unsigned OpIdx,
Value |= M68k::swapWord<value_t>(static_cast<value_t>(MCO.getImm()));
} else if (MCO.isExpr()) {
const MCExpr *Expr = MCO.getExpr();
+ unsigned InsertByte = getBytePosition<Size>(InsertPos);
- // Absolute address
+ if (const auto *SRE = dyn_cast<MCSymbolRefExpr>(Expr)) {
+ if ((unsigned)SRE->getKind() == M68kII::MO_GOTPCREL) {
+ // Size here is the template parameter <unsigned Size>
+ // We must ensure we are hitting the 32-bit version of this function
+ addFixup(Fixups, InsertByte, Expr, MCFixupKind(FK_Data_4));
+ return;
+ }
+ }
+
+ // Absolute address logic follows...
int64_t Addr;
if (Expr->evaluateAsAbsolute(Addr)) {
Value |= M68k::swapWord<value_t>(static_cast<value_t>(Addr));
return;
}
- // Relocatable address
- unsigned InsertByte = getBytePosition<Size>(InsertPos);
addFixup(Fixups, InsertByte, Expr, MCFixup::getDataKindForSize(Size / 8));
}
}
```
I'll attach a cleaned up version shortly.
https://github.com/llvm/llvm-project/pull/119803
More information about the llvm-commits
mailing list