1 //===-- VEISelDAGToDAG.cpp - A dag to dag inst selector for VE ------------===// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines an instruction selector for the VE target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "VE.h" 14 #include "VETargetMachine.h" 15 #include "llvm/CodeGen/MachineRegisterInfo.h" 16 #include "llvm/CodeGen/SelectionDAGISel.h" 17 #include "llvm/IR/Intrinsics.h" 18 #include "llvm/Support/Debug.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include "llvm/Support/raw_ostream.h" 21 using namespace llvm; 22 23 #define DEBUG_TYPE "ve-isel" 24 #define PASS_NAME "VE DAG->DAG Pattern Instruction Selection" 25 26 //===--------------------------------------------------------------------===// 27 /// VEDAGToDAGISel - VE specific code to select VE machine 28 /// instructions for SelectionDAG operations. 29 /// 30 namespace { 31 class VEDAGToDAGISel : public SelectionDAGISel { 32 /// Subtarget - Keep a pointer to the VE Subtarget around so that we can 33 /// make the right decision when generating code for different targets. 34 const VESubtarget *Subtarget; 35 36 public: 37 VEDAGToDAGISel() = delete; 38 39 explicit VEDAGToDAGISel(VETargetMachine &tm) : SelectionDAGISel(tm) {} 40 41 bool runOnMachineFunction(MachineFunction &MF) override { 42 Subtarget = &MF.getSubtarget<VESubtarget>(); 43 return SelectionDAGISel::runOnMachineFunction(MF); 44 } 45 46 void Select(SDNode *N) override; 47 48 // Complex Pattern Selectors. 49 bool selectADDRrri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset); 50 bool selectADDRrii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset); 51 bool selectADDRzri(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset); 52 bool selectADDRzii(SDValue N, SDValue &Base, SDValue &Index, SDValue &Offset); 53 bool selectADDRri(SDValue N, SDValue &Base, SDValue &Offset); 54 bool selectADDRzi(SDValue N, SDValue &Base, SDValue &Offset); 55 56 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 57 /// inline asm expressions. 58 bool SelectInlineAsmMemoryOperand(const SDValue &Op, 59 InlineAsm::ConstraintCode ConstraintID, 60 std::vector<SDValue> &OutOps) override; 61 62 // Include the pieces autogenerated from the target description. 63 #include "VEGenDAGISel.inc" 64 65 private: 66 SDNode *getGlobalBaseReg(); 67 68 bool matchADDRrr(SDValue N, SDValue &Base, SDValue &Index); 69 bool matchADDRri(SDValue N, SDValue &Base, SDValue &Offset); 70 }; 71 72 class VEDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 73 public: 74 static char ID; 75 explicit VEDAGToDAGISelLegacy(VETargetMachine &tm) 76 : SelectionDAGISelLegacy(ID, std::make_unique<VEDAGToDAGISel>(tm)) {} 77 }; 78 } // end anonymous namespace 79 80 char VEDAGToDAGISelLegacy::ID = 0; 81 82 INITIALIZE_PASS(VEDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 83 84 bool VEDAGToDAGISel::selectADDRrri(SDValue Addr, SDValue &Base, SDValue &Index, 85 SDValue &Offset) { 86 if (Addr.getOpcode() == ISD::FrameIndex) 87 return false; 88 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 89 Addr.getOpcode() == ISD::TargetGlobalAddress || 90 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 91 return false; // direct calls. 92 93 SDValue LHS, RHS; 94 if (matchADDRri(Addr, LHS, RHS)) { 95 if (matchADDRrr(LHS, Base, Index)) { 96 Offset = RHS; 97 return true; 98 } 99 // Return false to try selectADDRrii. 100 return false; 101 } 102 if (matchADDRrr(Addr, LHS, RHS)) { 103 // If the input is a pair of a frame-index and a register, move a 104 // frame-index to LHS. This generates MI with following operands. 105 // %dest, #FI, %reg, offset 106 // In the eliminateFrameIndex, above MI is converted to the following. 107 // %dest, %fp, %reg, fi_offset + offset 108 if (isa<FrameIndexSDNode>(RHS)) 109 std::swap(LHS, RHS); 110 111 if (matchADDRri(RHS, Index, Offset)) { 112 Base = LHS; 113 return true; 114 } 115 if (matchADDRri(LHS, Base, Offset)) { 116 Index = RHS; 117 return true; 118 } 119 Base = LHS; 120 Index = RHS; 121 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 122 return true; 123 } 124 return false; // Let the reg+imm(=0) pattern catch this! 125 } 126 127 bool VEDAGToDAGISel::selectADDRrii(SDValue Addr, SDValue &Base, SDValue &Index, 128 SDValue &Offset) { 129 if (matchADDRri(Addr, Base, Offset)) { 130 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 131 return true; 132 } 133 134 Base = Addr; 135 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 136 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 137 return true; 138 } 139 140 bool VEDAGToDAGISel::selectADDRzri(SDValue Addr, SDValue &Base, SDValue &Index, 141 SDValue &Offset) { 142 // Prefer ADDRrii. 143 return false; 144 } 145 146 bool VEDAGToDAGISel::selectADDRzii(SDValue Addr, SDValue &Base, SDValue &Index, 147 SDValue &Offset) { 148 if (isa<FrameIndexSDNode>(Addr)) 149 return false; 150 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 151 Addr.getOpcode() == ISD::TargetGlobalAddress || 152 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 153 return false; // direct calls. 154 155 if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) { 156 if (isInt<32>(CN->getSExtValue())) { 157 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 158 Index = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 159 Offset = 160 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32); 161 return true; 162 } 163 } 164 return false; 165 } 166 167 bool VEDAGToDAGISel::selectADDRri(SDValue Addr, SDValue &Base, 168 SDValue &Offset) { 169 if (matchADDRri(Addr, Base, Offset)) 170 return true; 171 172 Base = Addr; 173 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 174 return true; 175 } 176 177 bool VEDAGToDAGISel::selectADDRzi(SDValue Addr, SDValue &Base, 178 SDValue &Offset) { 179 if (isa<FrameIndexSDNode>(Addr)) 180 return false; 181 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 182 Addr.getOpcode() == ISD::TargetGlobalAddress || 183 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 184 return false; // direct calls. 185 186 if (auto *CN = dyn_cast<ConstantSDNode>(Addr)) { 187 if (isInt<32>(CN->getSExtValue())) { 188 Base = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 189 Offset = 190 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32); 191 return true; 192 } 193 } 194 return false; 195 } 196 197 bool VEDAGToDAGISel::matchADDRrr(SDValue Addr, SDValue &Base, SDValue &Index) { 198 if (isa<FrameIndexSDNode>(Addr)) 199 return false; 200 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 201 Addr.getOpcode() == ISD::TargetGlobalAddress || 202 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 203 return false; // direct calls. 204 205 if (Addr.getOpcode() == ISD::ADD) { 206 ; // Nothing to do here. 207 } else if (Addr.getOpcode() == ISD::OR) { 208 // We want to look through a transform in InstCombine and DAGCombiner that 209 // turns 'add' into 'or', so we can treat this 'or' exactly like an 'add'. 210 if (!CurDAG->haveNoCommonBitsSet(Addr.getOperand(0), Addr.getOperand(1))) 211 return false; 212 } else { 213 return false; 214 } 215 216 if (Addr.getOperand(0).getOpcode() == VEISD::Lo || 217 Addr.getOperand(1).getOpcode() == VEISD::Lo) 218 return false; // Let the LEASL patterns catch this! 219 220 Base = Addr.getOperand(0); 221 Index = Addr.getOperand(1); 222 return true; 223 } 224 225 bool VEDAGToDAGISel::matchADDRri(SDValue Addr, SDValue &Base, SDValue &Offset) { 226 auto AddrTy = Addr->getValueType(0); 227 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 228 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy); 229 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 230 return true; 231 } 232 if (Addr.getOpcode() == ISD::TargetExternalSymbol || 233 Addr.getOpcode() == ISD::TargetGlobalAddress || 234 Addr.getOpcode() == ISD::TargetGlobalTLSAddress) 235 return false; // direct calls. 236 237 if (CurDAG->isBaseWithConstantOffset(Addr)) { 238 ConstantSDNode *CN = cast<ConstantSDNode>(Addr.getOperand(1)); 239 if (isInt<32>(CN->getSExtValue())) { 240 if (FrameIndexSDNode *FIN = 241 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 242 // Constant offset from frame ref. 243 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), AddrTy); 244 } else { 245 Base = Addr.getOperand(0); 246 } 247 Offset = 248 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), MVT::i32); 249 return true; 250 } 251 } 252 return false; 253 } 254 255 void VEDAGToDAGISel::Select(SDNode *N) { 256 SDLoc dl(N); 257 if (N->isMachineOpcode()) { 258 N->setNodeId(-1); 259 return; // Already selected. 260 } 261 262 switch (N->getOpcode()) { 263 264 // Late eliminate the LEGALAVL wrapper 265 case VEISD::LEGALAVL: 266 ReplaceNode(N, N->getOperand(0).getNode()); 267 return; 268 269 // Lower (broadcast 1) and (broadcast 0) to VM[P]0 270 case VEISD::VEC_BROADCAST: { 271 MVT SplatResTy = N->getSimpleValueType(0); 272 if (SplatResTy.getVectorElementType() != MVT::i1) 273 break; 274 275 // Constant non-zero broadcast. 276 auto BConst = dyn_cast<ConstantSDNode>(N->getOperand(0)); 277 if (!BConst) 278 break; 279 bool BCTrueMask = (BConst->getSExtValue() != 0); 280 if (!BCTrueMask) 281 break; 282 283 // Packed or non-packed. 284 SDValue New; 285 if (SplatResTy.getVectorNumElements() == StandardVectorWidth) { 286 New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VM0, 287 MVT::v256i1); 288 } else if (SplatResTy.getVectorNumElements() == PackedVectorWidth) { 289 New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), SDLoc(N), VE::VMP0, 290 MVT::v512i1); 291 } else 292 break; 293 294 // Replace. 295 ReplaceNode(N, New.getNode()); 296 return; 297 } 298 299 case VEISD::GLOBAL_BASE_REG: 300 ReplaceNode(N, getGlobalBaseReg()); 301 return; 302 } 303 304 SelectCode(N); 305 } 306 307 /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for 308 /// inline asm expressions. 309 bool VEDAGToDAGISel::SelectInlineAsmMemoryOperand( 310 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 311 std::vector<SDValue> &OutOps) { 312 SDValue Op0, Op1; 313 switch (ConstraintID) { 314 default: 315 llvm_unreachable("Unexpected asm memory constraint"); 316 case InlineAsm::ConstraintCode::o: 317 case InlineAsm::ConstraintCode::m: // memory 318 // Try to match ADDRri since reg+imm style is safe for all VE instructions 319 // with a memory operand. 320 if (selectADDRri(Op, Op0, Op1)) { 321 OutOps.push_back(Op0); 322 OutOps.push_back(Op1); 323 return false; 324 } 325 // Otherwise, require the address to be in a register and immediate 0. 326 OutOps.push_back(Op); 327 OutOps.push_back(CurDAG->getTargetConstant(0, SDLoc(Op), MVT::i32)); 328 return false; 329 } 330 return true; 331 } 332 333 SDNode *VEDAGToDAGISel::getGlobalBaseReg() { 334 Register GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF); 335 return CurDAG 336 ->getRegister(GlobalBaseReg, TLI->getPointerTy(CurDAG->getDataLayout())) 337 .getNode(); 338 } 339 340 /// createVEISelDag - This pass converts a legalized DAG into a 341 /// VE-specific DAG, ready for instruction scheduling. 342 /// 343 FunctionPass *llvm::createVEISelDag(VETargetMachine &TM) { 344 return new VEDAGToDAGISelLegacy(TM); 345 } 346