306 lines · cpp
1//===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup Pass -------===//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// This pass is to address a situation that appears after register allocation9// every now and then, namely a register copy from a source that was defined10// as an immediate value in the same block (usually just before the copy).11//12// Here is an example of actual code emitted that shows this problem:13//14// .LBB0_5:15// {16// r5 = zxtb(r8)17// r6 = or(r6, ##12345)18// }19// {20// r3 = xor(r1, r2)21// r1 = #0 <-- r1 set to #022// }23// {24// r7 = r1 <-- r7 set to r125// r0 = zxtb(r3)26// }27 28#include "Hexagon.h"29#include "HexagonTargetMachine.h"30 31#include "llvm/CodeGen/LiveIntervals.h"32#include "llvm/CodeGen/MachineFunction.h"33#include "llvm/CodeGen/MachineInstrBuilder.h"34#include "llvm/CodeGen/Passes.h"35#include "llvm/CodeGen/TargetInstrInfo.h"36#include "llvm/CodeGen/TargetRegisterInfo.h"37 38using namespace llvm;39 40#define DEBUG_TYPE "tfr-cleanup"41 42namespace {43class HexagonTfrCleanup : public MachineFunctionPass {44public:45 static char ID;46 HexagonTfrCleanup() : MachineFunctionPass(ID) {}47 StringRef getPassName() const override { return "Hexagon TFR Cleanup"; }48 void getAnalysisUsage(AnalysisUsage &AU) const override {49 AU.setPreservesAll();50 MachineFunctionPass::getAnalysisUsage(AU);51 }52 bool runOnMachineFunction(MachineFunction &MF) override;53 54private:55 const HexagonInstrInfo *HII = nullptr;56 const TargetRegisterInfo *TRI = nullptr;57 58 typedef DenseMap<unsigned, uint64_t> ImmediateMap;59 60 bool isIntReg(unsigned Reg, bool &Is32);61 void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap);62 bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap);63 bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap);64 bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes);65 bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes);66};67} // namespace68 69char HexagonTfrCleanup::ID = 0;70 71namespace llvm {72char &HexagonTfrCleanupID = HexagonTfrCleanup::ID;73}74 75bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) {76 Is32 = Hexagon::IntRegsRegClass.contains(Reg);77 return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg);78}79 80// Assign given value V32 to the specified the register R32 in the map. Only81// 32-bit registers are valid arguments.82void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) {83 IMap[R32] = V32;84}85 86// Retrieve a value of the provided register Reg and store it into Val.87// Return "true" if a value was found, "false" otherwise.88bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val,89 ImmediateMap &IMap) {90 bool Is32;91 if (!isIntReg(Reg, Is32))92 return false;93 94 if (Is32) {95 ImmediateMap::iterator F = IMap.find(Reg);96 if (F == IMap.end())97 return false;98 Val = F->second;99 return true;100 }101 102 // For 64-bit registers, compose the value from the values of its103 // subregisters.104 unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo);105 unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi);106 ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH);107 if (FL == IMap.end() || FH == IMap.end())108 return false;109 Val = (FH->second << 32) | FL->second;110 return true;111}112 113// Process an instruction and record the relevant information in the imme-114// diate map.115bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) {116 using namespace Hexagon;117 118 if (MI->isCall()) {119 IMap.clear();120 return true;121 }122 123 // If this is an instruction that loads a constant into a register,124 // record this information in IMap.125 unsigned Opc = MI->getOpcode();126 if (Opc == A2_tfrsi || Opc == A2_tfrpi) {127 unsigned DefR = MI->getOperand(0).getReg();128 bool Is32;129 if (!isIntReg(DefR, Is32))130 return false;131 if (!MI->getOperand(1).isImm()) {132 if (!Is32) {133 IMap.erase(TRI->getSubReg(DefR, isub_lo));134 IMap.erase(TRI->getSubReg(DefR, isub_hi));135 } else {136 IMap.erase(DefR);137 }138 return false;139 }140 uint64_t Val = MI->getOperand(1).getImm();141 // If it's a 64-bit register, break it up into subregisters.142 if (!Is32) {143 uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU);144 setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap);145 setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap);146 } else {147 setReg(DefR, Val, IMap);148 }149 return true;150 }151 152 // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap.153 for (MachineInstr::mop_iterator Mo = MI->operands_begin(),154 E = MI->operands_end();155 Mo != E; ++Mo) {156 if (Mo->isRegMask()) {157 IMap.clear();158 return true;159 }160 if (!Mo->isReg() || !Mo->isDef())161 continue;162 unsigned R = Mo->getReg();163 for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR)164 IMap.erase(*AR);165 }166 return true;167}168 169// Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that170// has a known constant value.171bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap,172 SlotIndexes *Indexes) {173 using namespace Hexagon;174 unsigned Opc = MI->getOpcode();175 switch (Opc) {176 case A2_tfr:177 case A2_tfrp:178 case COPY:179 break;180 default:181 return false;182 }183 184 unsigned DstR = MI->getOperand(0).getReg();185 unsigned SrcR = MI->getOperand(1).getReg();186 bool Tmp, Is32;187 if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp))188 return false;189 assert(Tmp == Is32 && "Register size mismatch");190 uint64_t Val;191 bool Found = getReg(SrcR, Val, IMap);192 if (!Found)193 return false;194 195 MachineBasicBlock &B = *MI->getParent();196 DebugLoc DL = MI->getDebugLoc();197 int64_t SVal = Is32 ? int32_t(Val) : Val;198 auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>();199 MachineInstr *NewMI;200 if (Is32)201 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal);202 else if (isInt<8>(SVal))203 NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal);204 else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL)))205 NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR)206 .addImm(int32_t(SVal >> 32))207 .addImm(int32_t(Val & 0xFFFFFFFFLL));208 else if (HST.isTinyCore())209 // Disable generating CONST64 since it requires load resource.210 return false;211 else212 NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val);213 214 // Replace the MI to reuse the same slot index215 if (Indexes)216 Indexes->replaceMachineInstrInMaps(*MI, *NewMI);217 MI->eraseFromParent();218 return true;219}220 221// Remove the instruction if it is a self-assignment.222bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI,223 SlotIndexes *Indexes) {224 unsigned Opc = MI->getOpcode();225 unsigned DefR, SrcR;226 bool IsUndef = false;227 switch (Opc) {228 case Hexagon::A2_tfr:229 // Rd = Rd230 DefR = MI->getOperand(0).getReg();231 SrcR = MI->getOperand(1).getReg();232 IsUndef = MI->getOperand(1).isUndef();233 break;234 case Hexagon::A2_tfrt:235 case Hexagon::A2_tfrf:236 // if ([!]Pu) Rd = Rd237 DefR = MI->getOperand(0).getReg();238 SrcR = MI->getOperand(2).getReg();239 IsUndef = MI->getOperand(2).isUndef();240 break;241 default:242 return false;243 }244 if (DefR != SrcR)245 return false;246 if (IsUndef) {247 MachineBasicBlock &B = *MI->getParent();248 DebugLoc DL = MI->getDebugLoc();249 auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR);250 for (auto &Op : MI->operands())251 if (Op.isReg() && Op.isDef() && Op.isImplicit())252 DefI->addOperand(Op);253 }254 255 if (Indexes)256 Indexes->removeMachineInstrFromMaps(*MI);257 MI->eraseFromParent();258 return true;259}260 261bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) {262 bool Changed = false;263 // Map: 32-bit register -> immediate value.264 // 64-bit registers are stored through their subregisters.265 ImmediateMap IMap;266 auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>();267 SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr;268 269 auto &HST = MF.getSubtarget<HexagonSubtarget>();270 HII = HST.getInstrInfo();271 TRI = HST.getRegisterInfo();272 273 for (MachineBasicBlock &B : MF) {274 MachineBasicBlock::iterator J, F, NextJ;275 IMap.clear();276 bool Inserted = false, Erased = false;277 for (J = B.begin(), F = B.end(); J != F; J = NextJ) {278 NextJ = std::next(J);279 MachineInstr *MI = &*J;280 bool E = eraseIfRedundant(MI, Indexes);281 Erased |= E;282 if (E)283 continue;284 Inserted |= rewriteIfImm(MI, IMap, Indexes);285 MachineBasicBlock::iterator NewJ = std::prev(NextJ);286 updateImmMap(&*NewJ, IMap);287 }288 bool BlockC = Inserted | Erased;289 Changed |= BlockC;290 if (BlockC && Indexes)291 Indexes->repairIndexesInRange(&B, B.begin(), B.end());292 }293 294 return Changed;295}296 297//===----------------------------------------------------------------------===//298// Public Constructor Functions299//===----------------------------------------------------------------------===//300INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false,301 false)302 303FunctionPass *llvm::createHexagonTfrCleanup() {304 return new HexagonTfrCleanup();305}306