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