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