1 //===-- llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h --===========// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // This file contains some helper functions which try to cleanup artifacts 10 // such as G_TRUNCs/G_[ZSA]EXTENDS that were created during legalization to make 11 // the types match. This file also contains some combines of merges that happens 12 // at the end of the legalization. 13 //===----------------------------------------------------------------------===// 14 15 #include "llvm/CodeGen/GlobalISel/Legalizer.h" 16 #include "llvm/CodeGen/GlobalISel/LegalizerInfo.h" 17 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 18 #include "llvm/CodeGen/GlobalISel/Utils.h" 19 #include "llvm/CodeGen/MachineRegisterInfo.h" 20 #include "llvm/Support/Debug.h" 21 22 #define DEBUG_TYPE "legalizer" 23 24 namespace llvm { 25 class LegalizationArtifactCombiner { 26 MachineIRBuilder &Builder; 27 MachineRegisterInfo &MRI; 28 const LegalizerInfo &LI; 29 30 public: LegalizationArtifactCombiner(MachineIRBuilder & B,MachineRegisterInfo & MRI,const LegalizerInfo & LI)31 LegalizationArtifactCombiner(MachineIRBuilder &B, MachineRegisterInfo &MRI, 32 const LegalizerInfo &LI) 33 : Builder(B), MRI(MRI), LI(LI) {} 34 tryCombineAnyExt(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)35 bool tryCombineAnyExt(MachineInstr &MI, 36 SmallVectorImpl<MachineInstr *> &DeadInsts) { 37 if (MI.getOpcode() != TargetOpcode::G_ANYEXT) 38 return false; 39 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_TRUNC, 40 MI.getOperand(1).getReg(), MRI)) { 41 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); 42 unsigned DstReg = MI.getOperand(0).getReg(); 43 unsigned SrcReg = DefMI->getOperand(1).getReg(); 44 Builder.setInstr(MI); 45 // We get a copy/trunc/extend depending on the sizes 46 Builder.buildAnyExtOrTrunc(DstReg, SrcReg); 47 markInstAndDefDead(MI, *DefMI, DeadInsts); 48 return true; 49 } 50 return tryFoldImplicitDef(MI, DeadInsts); 51 } 52 tryCombineZExt(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)53 bool tryCombineZExt(MachineInstr &MI, 54 SmallVectorImpl<MachineInstr *> &DeadInsts) { 55 56 if (MI.getOpcode() != TargetOpcode::G_ZEXT) 57 return false; 58 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_TRUNC, 59 MI.getOperand(1).getReg(), MRI)) { 60 unsigned DstReg = MI.getOperand(0).getReg(); 61 LLT DstTy = MRI.getType(DstReg); 62 if (isInstUnsupported({TargetOpcode::G_AND, {DstTy}}) || 63 isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) 64 return false; 65 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); 66 Builder.setInstr(MI); 67 unsigned ZExtSrc = MI.getOperand(1).getReg(); 68 LLT ZExtSrcTy = MRI.getType(ZExtSrc); 69 APInt Mask = APInt::getAllOnesValue(ZExtSrcTy.getSizeInBits()); 70 auto MaskCstMIB = Builder.buildConstant(DstTy, Mask.getZExtValue()); 71 unsigned TruncSrc = DefMI->getOperand(1).getReg(); 72 // We get a copy/trunc/extend depending on the sizes 73 auto SrcCopyOrTrunc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc); 74 Builder.buildAnd(DstReg, SrcCopyOrTrunc, MaskCstMIB); 75 markInstAndDefDead(MI, *DefMI, DeadInsts); 76 return true; 77 } 78 return tryFoldImplicitDef(MI, DeadInsts); 79 } 80 tryCombineSExt(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)81 bool tryCombineSExt(MachineInstr &MI, 82 SmallVectorImpl<MachineInstr *> &DeadInsts) { 83 84 if (MI.getOpcode() != TargetOpcode::G_SEXT) 85 return false; 86 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_TRUNC, 87 MI.getOperand(1).getReg(), MRI)) { 88 unsigned DstReg = MI.getOperand(0).getReg(); 89 LLT DstTy = MRI.getType(DstReg); 90 if (isInstUnsupported({TargetOpcode::G_SHL, {DstTy}}) || 91 isInstUnsupported({TargetOpcode::G_ASHR, {DstTy}}) || 92 isInstUnsupported({TargetOpcode::G_CONSTANT, {DstTy}})) 93 return false; 94 LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI;); 95 Builder.setInstr(MI); 96 unsigned SExtSrc = MI.getOperand(1).getReg(); 97 LLT SExtSrcTy = MRI.getType(SExtSrc); 98 unsigned SizeDiff = DstTy.getSizeInBits() - SExtSrcTy.getSizeInBits(); 99 auto SizeDiffMIB = Builder.buildConstant(DstTy, SizeDiff); 100 unsigned TruncSrcReg = DefMI->getOperand(1).getReg(); 101 // We get a copy/trunc/extend depending on the sizes 102 auto SrcCopyExtOrTrunc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrcReg); 103 auto ShlMIB = Builder.buildInstr(TargetOpcode::G_SHL, DstTy, 104 SrcCopyExtOrTrunc, SizeDiffMIB); 105 Builder.buildInstr(TargetOpcode::G_ASHR, DstReg, ShlMIB, SizeDiffMIB); 106 markInstAndDefDead(MI, *DefMI, DeadInsts); 107 return true; 108 } 109 return tryFoldImplicitDef(MI, DeadInsts); 110 } 111 112 /// Try to fold sb = EXTEND (G_IMPLICIT_DEF sa) -> sb = G_IMPLICIT_DEF tryFoldImplicitDef(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)113 bool tryFoldImplicitDef(MachineInstr &MI, 114 SmallVectorImpl<MachineInstr *> &DeadInsts) { 115 unsigned Opcode = MI.getOpcode(); 116 if (Opcode != TargetOpcode::G_ANYEXT && Opcode != TargetOpcode::G_ZEXT && 117 Opcode != TargetOpcode::G_SEXT) 118 return false; 119 120 if (MachineInstr *DefMI = getOpcodeDef(TargetOpcode::G_IMPLICIT_DEF, 121 MI.getOperand(1).getReg(), MRI)) { 122 unsigned DstReg = MI.getOperand(0).getReg(); 123 LLT DstTy = MRI.getType(DstReg); 124 if (isInstUnsupported({TargetOpcode::G_IMPLICIT_DEF, {DstTy}})) 125 return false; 126 LLVM_DEBUG(dbgs() << ".. Combine EXT(IMPLICIT_DEF) " << MI;); 127 Builder.setInstr(MI); 128 Builder.buildInstr(TargetOpcode::G_IMPLICIT_DEF, DstReg); 129 markInstAndDefDead(MI, *DefMI, DeadInsts); 130 return true; 131 } 132 return false; 133 } 134 tryCombineMerges(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)135 bool tryCombineMerges(MachineInstr &MI, 136 SmallVectorImpl<MachineInstr *> &DeadInsts) { 137 138 if (MI.getOpcode() != TargetOpcode::G_UNMERGE_VALUES) 139 return false; 140 141 unsigned NumDefs = MI.getNumOperands() - 1; 142 MachineInstr *MergeI = getOpcodeDef(TargetOpcode::G_MERGE_VALUES, 143 MI.getOperand(NumDefs).getReg(), MRI); 144 if (!MergeI) 145 return false; 146 147 const unsigned NumMergeRegs = MergeI->getNumOperands() - 1; 148 149 if (NumMergeRegs < NumDefs) { 150 if (NumDefs % NumMergeRegs != 0) 151 return false; 152 153 Builder.setInstr(MI); 154 // Transform to UNMERGEs, for example 155 // %1 = G_MERGE_VALUES %4, %5 156 // %9, %10, %11, %12 = G_UNMERGE_VALUES %1 157 // to 158 // %9, %10 = G_UNMERGE_VALUES %4 159 // %11, %12 = G_UNMERGE_VALUES %5 160 161 const unsigned NewNumDefs = NumDefs / NumMergeRegs; 162 for (unsigned Idx = 0; Idx < NumMergeRegs; ++Idx) { 163 SmallVector<unsigned, 2> DstRegs; 164 for (unsigned j = 0, DefIdx = Idx * NewNumDefs; j < NewNumDefs; 165 ++j, ++DefIdx) 166 DstRegs.push_back(MI.getOperand(DefIdx).getReg()); 167 168 Builder.buildUnmerge(DstRegs, MergeI->getOperand(Idx + 1).getReg()); 169 } 170 171 } else if (NumMergeRegs > NumDefs) { 172 if (NumMergeRegs % NumDefs != 0) 173 return false; 174 175 Builder.setInstr(MI); 176 // Transform to MERGEs 177 // %6 = G_MERGE_VALUES %17, %18, %19, %20 178 // %7, %8 = G_UNMERGE_VALUES %6 179 // to 180 // %7 = G_MERGE_VALUES %17, %18 181 // %8 = G_MERGE_VALUES %19, %20 182 183 const unsigned NumRegs = NumMergeRegs / NumDefs; 184 for (unsigned DefIdx = 0; DefIdx < NumDefs; ++DefIdx) { 185 SmallVector<unsigned, 2> Regs; 186 for (unsigned j = 0, Idx = NumRegs * DefIdx + 1; j < NumRegs; 187 ++j, ++Idx) 188 Regs.push_back(MergeI->getOperand(Idx).getReg()); 189 190 Builder.buildMerge(MI.getOperand(DefIdx).getReg(), Regs); 191 } 192 193 } else { 194 // FIXME: is a COPY appropriate if the types mismatch? We know both 195 // registers are allocatable by now. 196 if (MRI.getType(MI.getOperand(0).getReg()) != 197 MRI.getType(MergeI->getOperand(1).getReg())) 198 return false; 199 200 for (unsigned Idx = 0; Idx < NumDefs; ++Idx) 201 MRI.replaceRegWith(MI.getOperand(Idx).getReg(), 202 MergeI->getOperand(Idx + 1).getReg()); 203 } 204 205 markInstAndDefDead(MI, *MergeI, DeadInsts); 206 return true; 207 } 208 209 /// Try to combine away MI. 210 /// Returns true if it combined away the MI. 211 /// Adds instructions that are dead as a result of the combine 212 /// into DeadInsts, which can include MI. tryCombineInstruction(MachineInstr & MI,SmallVectorImpl<MachineInstr * > & DeadInsts)213 bool tryCombineInstruction(MachineInstr &MI, 214 SmallVectorImpl<MachineInstr *> &DeadInsts) { 215 switch (MI.getOpcode()) { 216 default: 217 return false; 218 case TargetOpcode::G_ANYEXT: 219 return tryCombineAnyExt(MI, DeadInsts); 220 case TargetOpcode::G_ZEXT: 221 return tryCombineZExt(MI, DeadInsts); 222 case TargetOpcode::G_SEXT: 223 return tryCombineSExt(MI, DeadInsts); 224 case TargetOpcode::G_UNMERGE_VALUES: 225 return tryCombineMerges(MI, DeadInsts); 226 case TargetOpcode::G_TRUNC: { 227 bool Changed = false; 228 for (auto &Use : MRI.use_instructions(MI.getOperand(0).getReg())) 229 Changed |= tryCombineInstruction(Use, DeadInsts); 230 return Changed; 231 } 232 } 233 } 234 235 private: 236 /// Mark MI as dead. If a def of one of MI's operands, DefMI, would also be 237 /// dead due to MI being killed, then mark DefMI as dead too. 238 /// Some of the combines (extends(trunc)), try to walk through redundant 239 /// copies in between the extends and the truncs, and this attempts to collect 240 /// the in between copies if they're dead. markInstAndDefDead(MachineInstr & MI,MachineInstr & DefMI,SmallVectorImpl<MachineInstr * > & DeadInsts)241 void markInstAndDefDead(MachineInstr &MI, MachineInstr &DefMI, 242 SmallVectorImpl<MachineInstr *> &DeadInsts) { 243 DeadInsts.push_back(&MI); 244 245 // Collect all the copy instructions that are made dead, due to deleting 246 // this instruction. Collect all of them until the Trunc(DefMI). 247 // Eg, 248 // %1(s1) = G_TRUNC %0(s32) 249 // %2(s1) = COPY %1(s1) 250 // %3(s1) = COPY %2(s1) 251 // %4(s32) = G_ANYEXT %3(s1) 252 // In this case, we would have replaced %4 with a copy of %0, 253 // and as a result, %3, %2, %1 are dead. 254 MachineInstr *PrevMI = &MI; 255 while (PrevMI != &DefMI) { 256 unsigned PrevRegSrc = 257 PrevMI->getOperand(PrevMI->getNumOperands() - 1).getReg(); 258 MachineInstr *TmpDef = MRI.getVRegDef(PrevRegSrc); 259 if (MRI.hasOneUse(PrevRegSrc)) { 260 if (TmpDef != &DefMI) { 261 assert(TmpDef->getOpcode() == TargetOpcode::COPY && 262 "Expecting copy here"); 263 DeadInsts.push_back(TmpDef); 264 } 265 } else 266 break; 267 PrevMI = TmpDef; 268 } 269 if (PrevMI == &DefMI && MRI.hasOneUse(DefMI.getOperand(0).getReg())) 270 DeadInsts.push_back(&DefMI); 271 } 272 273 /// Checks if the target legalizer info has specified anything about the 274 /// instruction, or if unsupported. isInstUnsupported(const LegalityQuery & Query)275 bool isInstUnsupported(const LegalityQuery &Query) const { 276 using namespace LegalizeActions; 277 auto Step = LI.getAction(Query); 278 return Step.Action == Unsupported || Step.Action == NotFound; 279 } 280 }; 281 282 } // namespace llvm 283