brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · b40e1f2 Raw
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