256 lines · cpp
1//===- X86SuppressAPXForReloc.cpp - Suppress APX features for relocations -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8/// \file9///10/// This pass is added to suppress APX features for relocations. It's used to11/// keep backward compatibility with old version of linker having no APX12/// support. It can be removed after APX support is included in the default13/// linker on OS.14///15//===----------------------------------------------------------------------===//16 17#include "X86.h"18#include "X86InstrInfo.h"19#include "X86RegisterInfo.h"20#include "X86Subtarget.h"21 22#include "llvm/CodeGen/MachineFunctionPass.h"23#include "llvm/CodeGen/MachineInstrBuilder.h"24#include "llvm/CodeGen/MachineOperand.h"25#include "llvm/CodeGen/MachineRegisterInfo.h"26#include "llvm/CodeGen/Passes.h"27#include "llvm/CodeGen/TargetRegisterInfo.h"28#include "llvm/Support/ErrorHandling.h"29 30using namespace llvm;31 32#define DEBUG_TYPE "x86-suppress-apx-for-relocation"33 34cl::opt<bool> X86EnableAPXForRelocation(35 "x86-enable-apx-for-relocation",36 cl::desc("Enable APX features (EGPR, NDD and NF) for instructions with "37 "relocations on x86-64 ELF"),38 cl::init(false));39 40namespace {41class X86SuppressAPXForRelocationPass : public MachineFunctionPass {42public:43 X86SuppressAPXForRelocationPass() : MachineFunctionPass(ID) {}44 45 StringRef getPassName() const override {46 return "X86 Suppress APX features for relocation";47 }48 49 bool runOnMachineFunction(MachineFunction &MF) override;50 51 static char ID;52};53} // namespace54 55char X86SuppressAPXForRelocationPass::ID = 0;56 57INITIALIZE_PASS_BEGIN(X86SuppressAPXForRelocationPass, DEBUG_TYPE,58 "X86 Suppress APX features for relocation", false, false)59INITIALIZE_PASS_END(X86SuppressAPXForRelocationPass, DEBUG_TYPE,60 "X86 Suppress APX features for relocation", false, false)61 62FunctionPass *llvm::createX86SuppressAPXForRelocationPass() {63 return new X86SuppressAPXForRelocationPass();64}65 66static void suppressEGPRRegClass(MachineRegisterInfo *MRI, MachineInstr &MI,67 const X86Subtarget &ST, unsigned int OpNum) {68 Register Reg = MI.getOperand(OpNum).getReg();69 if (!Reg.isVirtual()) {70 assert(!X86II::isApxExtendedReg(Reg) && "APX EGPR is used unexpectedly.");71 return;72 }73 const TargetRegisterClass *RC = MRI->getRegClass(Reg);74 const X86RegisterInfo *RI = ST.getRegisterInfo();75 const TargetRegisterClass *NewRC = RI->constrainRegClassToNonRex2(RC);76 MRI->setRegClass(Reg, NewRC);77}78 79// Suppress EGPR in operand 0 of uses to avoid APX relocation types emitted. The80// register in operand 0 of instruction with relocation may be replaced with81// operand 0 of uses which may be EGPR. That may lead to emit APX relocation82// types which breaks the backward compatibility with builtin linkers on83// existing OS. For example, the register in operand 0 of instruction with84// relocation is used in PHI instruction, and it may be replaced with operand 085// of PHI instruction after PHI elimination and Machine Copy Propagation pass.86static void suppressEGPRRegClassInRegAndUses(MachineRegisterInfo *MRI,87 MachineInstr &MI,88 const X86Subtarget &ST,89 unsigned int OpNum) {90 suppressEGPRRegClass(MRI, MI, ST, OpNum);91 Register Reg = MI.getOperand(OpNum).getReg();92 for (MachineInstr &Use : MRI->use_instructions(Reg))93 if (Use.getOpcode() == X86::PHI)94 suppressEGPRRegClass(MRI, Use, ST, 0);95}96 97static bool handleInstructionWithEGPR(MachineFunction &MF,98 const X86Subtarget &ST) {99 if (!ST.hasEGPR())100 return false;101 102 MachineRegisterInfo *MRI = &MF.getRegInfo();103 auto suppressEGPRInInstrWithReloc = [&](MachineInstr &MI,104 ArrayRef<unsigned> OpNoArray) {105 int MemOpNo = X86II::getMemoryOperandNo(MI.getDesc().TSFlags) +106 X86II::getOperandBias(MI.getDesc());107 const MachineOperand &MO = MI.getOperand(X86::AddrDisp + MemOpNo);108 if (MO.getTargetFlags() == X86II::MO_GOTTPOFF ||109 MO.getTargetFlags() == X86II::MO_GOTPCREL) {110 LLVM_DEBUG(dbgs() << "Transform instruction with relocation type:\n "111 << MI);112 for (unsigned OpNo : OpNoArray)113 suppressEGPRRegClassInRegAndUses(MRI, MI, ST, OpNo);114 LLVM_DEBUG(dbgs() << "to:\n " << MI << "\n");115 }116 };117 118 for (MachineBasicBlock &MBB : MF) {119 for (MachineInstr &MI : MBB) {120 unsigned Opcode = MI.getOpcode();121 switch (Opcode) {122 // For GOTPC32_TLSDESC, it's emitted with physical register (EAX/RAX) in123 // X86AsmPrinter::LowerTlsAddr, and there is no corresponding target124 // flag for it, so we don't need to handle LEA64r with TLSDESC and EGPR125 // in this pass (before emitting assembly).126 case X86::TEST32mr:127 case X86::TEST64mr: {128 suppressEGPRInInstrWithReloc(MI, {5});129 break;130 }131 case X86::CMP32rm:132 case X86::CMP64rm:133 case X86::MOV32rm:134 case X86::MOV64rm: {135 suppressEGPRInInstrWithReloc(MI, {0});136 break;137 }138 case X86::ADC32rm:139 case X86::ADD32rm:140 case X86::AND32rm:141 case X86::OR32rm:142 case X86::SBB32rm:143 case X86::SUB32rm:144 case X86::XOR32rm:145 case X86::ADC64rm:146 case X86::ADD64rm:147 case X86::AND64rm:148 case X86::OR64rm:149 case X86::SBB64rm:150 case X86::SUB64rm:151 case X86::XOR64rm: {152 suppressEGPRInInstrWithReloc(MI, {0, 1});153 break;154 }155 }156 }157 }158 return true;159}160 161static bool handleNDDOrNFInstructions(MachineFunction &MF,162 const X86Subtarget &ST) {163 if (!ST.hasNDD() && !ST.hasNF())164 return false;165 166 const X86InstrInfo *TII = ST.getInstrInfo();167 MachineRegisterInfo *MRI = &MF.getRegInfo();168 for (MachineBasicBlock &MBB : MF) {169 for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) {170 unsigned Opcode = MI.getOpcode();171 switch (Opcode) {172 case X86::ADD64rm_NF:173 case X86::ADD64mr_NF_ND:174 case X86::ADD64rm_NF_ND: {175 int MemOpNo = X86II::getMemoryOperandNo(MI.getDesc().TSFlags) +176 X86II::getOperandBias(MI.getDesc());177 const MachineOperand &MO = MI.getOperand(X86::AddrDisp + MemOpNo);178 if (MO.getTargetFlags() == X86II::MO_GOTTPOFF)179 llvm_unreachable("Unexpected NF instruction!");180 break;181 }182 case X86::ADD64rm_ND: {183 int MemOpNo = X86II::getMemoryOperandNo(MI.getDesc().TSFlags) +184 X86II::getOperandBias(MI.getDesc());185 const MachineOperand &MO = MI.getOperand(X86::AddrDisp + MemOpNo);186 if (MO.getTargetFlags() == X86II::MO_GOTTPOFF ||187 MO.getTargetFlags() == X86II::MO_GOTPCREL) {188 LLVM_DEBUG(dbgs() << "Transform instruction with relocation type:\n "189 << MI);190 Register Reg = MRI->createVirtualRegister(&X86::GR64_NOREX2RegClass);191 [[maybe_unused]] MachineInstrBuilder CopyMIB =192 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(TargetOpcode::COPY),193 Reg)194 .addReg(MI.getOperand(1).getReg());195 MI.getOperand(1).setReg(Reg);196 const MCInstrDesc &NewDesc = TII->get(X86::ADD64rm);197 MI.setDesc(NewDesc);198 suppressEGPRRegClassInRegAndUses(MRI, MI, ST, 0);199 MI.tieOperands(0, 1);200 LLVM_DEBUG(dbgs() << "to:\n " << *CopyMIB << "\n");201 LLVM_DEBUG(dbgs() << " " << MI << "\n");202 }203 break;204 }205 case X86::ADD64mr_ND: {206 int MemRefBegin = X86II::getMemoryOperandNo(MI.getDesc().TSFlags);207 const MachineOperand &MO = MI.getOperand(MemRefBegin + X86::AddrDisp);208 if (MO.getTargetFlags() == X86II::MO_GOTTPOFF) {209 LLVM_DEBUG(dbgs() << "Transform instruction with relocation type:\n "210 << MI);211 suppressEGPRRegClassInRegAndUses(MRI, MI, ST, 0);212 Register Reg = MRI->createVirtualRegister(&X86::GR64_NOREX2RegClass);213 [[maybe_unused]] MachineInstrBuilder CopyMIB =214 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(TargetOpcode::COPY),215 Reg)216 .addReg(MI.getOperand(6).getReg());217 MachineInstrBuilder NewMIB =218 BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(X86::ADD64rm),219 MI.getOperand(0).getReg())220 .addReg(Reg)221 .addReg(MI.getOperand(1).getReg())222 .addImm(MI.getOperand(2).getImm())223 .addReg(MI.getOperand(3).getReg())224 .add(MI.getOperand(4))225 .addReg(MI.getOperand(5).getReg());226 MachineOperand *FlagDef =227 MI.findRegisterDefOperand(X86::EFLAGS, /*TRI=*/nullptr);228 if (FlagDef && FlagDef->isDead()) {229 MachineOperand *NewFlagDef =230 NewMIB->findRegisterDefOperand(X86::EFLAGS, /*TRI=*/nullptr);231 if (NewFlagDef)232 NewFlagDef->setIsDead();233 }234 MI.eraseFromParent();235 LLVM_DEBUG(dbgs() << "to:\n " << *CopyMIB << "\n");236 LLVM_DEBUG(dbgs() << " " << *NewMIB << "\n");237 }238 break;239 }240 }241 }242 }243 return true;244}245 246bool X86SuppressAPXForRelocationPass::runOnMachineFunction(247 MachineFunction &MF) {248 if (X86EnableAPXForRelocation)249 return false;250 const X86Subtarget &ST = MF.getSubtarget<X86Subtarget>();251 bool Changed = handleInstructionWithEGPR(MF, ST);252 Changed |= handleNDDOrNFInstructions(MF, ST);253 254 return Changed;255}256