1 //===-- LanaiISelDAGToDAG.cpp - A dag to dag inst selector for Lanai ------===// 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 Lanai target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "LanaiAluCode.h" 14 #include "LanaiTargetMachine.h" 15 #include "llvm/CodeGen/MachineConstantPool.h" 16 #include "llvm/CodeGen/MachineFrameInfo.h" 17 #include "llvm/CodeGen/MachineFunction.h" 18 #include "llvm/CodeGen/SelectionDAGISel.h" 19 #include "llvm/IR/Instructions.h" 20 #include "llvm/IR/Type.h" 21 #include "llvm/Support/Debug.h" 22 #include "llvm/Support/ErrorHandling.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 using namespace llvm; 26 27 #define DEBUG_TYPE "lanai-isel" 28 #define PASS_NAME "Lanai DAG->DAG Pattern Instruction Selection" 29 30 //===----------------------------------------------------------------------===// 31 // Instruction Selector Implementation 32 //===----------------------------------------------------------------------===// 33 34 //===----------------------------------------------------------------------===// 35 // LanaiDAGToDAGISel - Lanai specific code to select Lanai machine 36 // instructions for SelectionDAG operations. 37 //===----------------------------------------------------------------------===// 38 namespace { 39 40 class LanaiDAGToDAGISel : public SelectionDAGISel { 41 public: 42 LanaiDAGToDAGISel() = delete; 43 44 explicit LanaiDAGToDAGISel(LanaiTargetMachine &TargetMachine) 45 : SelectionDAGISel(TargetMachine) {} 46 47 bool SelectInlineAsmMemoryOperand(const SDValue &Op, 48 InlineAsm::ConstraintCode ConstraintCode, 49 std::vector<SDValue> &OutOps) override; 50 51 private: 52 // Include the pieces autogenerated from the target description. 53 #include "LanaiGenDAGISel.inc" 54 55 // Instruction Selection not handled by the auto-generated tablgen 56 void Select(SDNode *N) override; 57 58 // Support functions for the opcodes of Instruction Selection 59 // not handled by the auto-generated tablgen 60 void selectFrameIndex(SDNode *N); 61 62 // Complex Pattern for address selection. 63 bool selectAddrRi(SDValue Addr, SDValue &Base, SDValue &Offset, 64 SDValue &AluOp); 65 bool selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, SDValue &AluOp); 66 bool selectAddrSls(SDValue Addr, SDValue &Offset); 67 bool selectAddrSpls(SDValue Addr, SDValue &Base, SDValue &Offset, 68 SDValue &AluOp); 69 70 // getI32Imm - Return a target constant with the specified value, of type i32. 71 inline SDValue getI32Imm(unsigned Imm, const SDLoc &DL) { 72 return CurDAG->getTargetConstant(Imm, DL, MVT::i32); 73 } 74 75 private: 76 bool selectAddrRiSpls(SDValue Addr, SDValue &Base, SDValue &Offset, 77 SDValue &AluOp, bool RiMode); 78 }; 79 80 bool canBeRepresentedAsSls(const ConstantSDNode &CN) { 81 // Fits in 21-bit signed immediate and two low-order bits are zero. 82 return isInt<21>(CN.getSExtValue()) && ((CN.getSExtValue() & 0x3) == 0); 83 } 84 85 class LanaiDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 86 public: 87 static char ID; 88 explicit LanaiDAGToDAGISelLegacy(LanaiTargetMachine &TM) 89 : SelectionDAGISelLegacy(ID, std::make_unique<LanaiDAGToDAGISel>(TM)) {} 90 }; 91 92 } // namespace 93 94 char LanaiDAGToDAGISelLegacy::ID = 0; 95 96 INITIALIZE_PASS(LanaiDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 97 98 // Helper functions for ComplexPattern used on LanaiInstrInfo 99 // Used on Lanai Load/Store instructions. 100 bool LanaiDAGToDAGISel::selectAddrSls(SDValue Addr, SDValue &Offset) { 101 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) { 102 SDLoc DL(Addr); 103 // Loading from a constant address. 104 if (canBeRepresentedAsSls(*CN)) { 105 int32_t Imm = CN->getSExtValue(); 106 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); 107 return true; 108 } 109 } 110 if (Addr.getOpcode() == ISD::OR && 111 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) { 112 Offset = Addr.getOperand(1).getOperand(0); 113 return true; 114 } 115 return false; 116 } 117 118 bool LanaiDAGToDAGISel::selectAddrRiSpls(SDValue Addr, SDValue &Base, 119 SDValue &Offset, SDValue &AluOp, 120 bool RiMode) { 121 SDLoc DL(Addr); 122 123 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr)) { 124 if (RiMode) { 125 // Fits in 16-bit signed immediate. 126 if (isInt<16>(CN->getSExtValue())) { 127 int16_t Imm = CN->getSExtValue(); 128 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); 129 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0)); 130 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); 131 return true; 132 } 133 // Allow SLS to match if the constant doesn't fit in 16 bits but can be 134 // represented as an SLS. 135 if (canBeRepresentedAsSls(*CN)) 136 return false; 137 } else { 138 // Fits in 10-bit signed immediate. 139 if (isInt<10>(CN->getSExtValue())) { 140 int16_t Imm = CN->getSExtValue(); 141 Offset = CurDAG->getTargetConstant(Imm, DL, CN->getValueType(0)); 142 Base = CurDAG->getRegister(Lanai::R0, CN->getValueType(0)); 143 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); 144 return true; 145 } 146 } 147 } 148 149 // if Address is FI, get the TargetFrameIndex. 150 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 151 Base = CurDAG->getTargetFrameIndex( 152 FIN->getIndex(), 153 getTargetLowering()->getPointerTy(CurDAG->getDataLayout())); 154 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); 155 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); 156 return true; 157 } 158 159 // Skip direct calls 160 if ((Addr.getOpcode() == ISD::TargetExternalSymbol || 161 Addr.getOpcode() == ISD::TargetGlobalAddress)) 162 return false; 163 164 // Address of the form imm + reg 165 ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); 166 if (AluOperator == ISD::ADD) { 167 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); 168 // Addresses of the form FI+const 169 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 170 if ((RiMode && isInt<16>(CN->getSExtValue())) || 171 (!RiMode && isInt<10>(CN->getSExtValue()))) { 172 // If the first operand is a FI, get the TargetFI Node 173 if (FrameIndexSDNode *FIN = 174 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) { 175 Base = CurDAG->getTargetFrameIndex( 176 FIN->getIndex(), 177 getTargetLowering()->getPointerTy(CurDAG->getDataLayout())); 178 } else { 179 Base = Addr.getOperand(0); 180 } 181 182 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), DL, MVT::i32); 183 return true; 184 } 185 } 186 187 // Let SLS match SMALL instead of RI. 188 if (AluOperator == ISD::OR && RiMode && 189 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) 190 return false; 191 192 Base = Addr; 193 Offset = CurDAG->getTargetConstant(0, DL, MVT::i32); 194 AluOp = CurDAG->getTargetConstant(LPAC::ADD, DL, MVT::i32); 195 return true; 196 } 197 198 bool LanaiDAGToDAGISel::selectAddrRi(SDValue Addr, SDValue &Base, 199 SDValue &Offset, SDValue &AluOp) { 200 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/true); 201 } 202 203 bool LanaiDAGToDAGISel::selectAddrSpls(SDValue Addr, SDValue &Base, 204 SDValue &Offset, SDValue &AluOp) { 205 return selectAddrRiSpls(Addr, Base, Offset, AluOp, /*RiMode=*/false); 206 } 207 208 namespace llvm { 209 namespace LPAC { 210 static AluCode isdToLanaiAluCode(ISD::NodeType Node_type) { 211 switch (Node_type) { 212 case ISD::ADD: 213 return AluCode::ADD; 214 case ISD::ADDE: 215 return AluCode::ADDC; 216 case ISD::SUB: 217 return AluCode::SUB; 218 case ISD::SUBE: 219 return AluCode::SUBB; 220 case ISD::AND: 221 return AluCode::AND; 222 case ISD::OR: 223 return AluCode::OR; 224 case ISD::XOR: 225 return AluCode::XOR; 226 case ISD::SHL: 227 return AluCode::SHL; 228 case ISD::SRL: 229 return AluCode::SRL; 230 case ISD::SRA: 231 return AluCode::SRA; 232 default: 233 return AluCode::UNKNOWN; 234 } 235 } 236 } // namespace LPAC 237 } // namespace llvm 238 239 bool LanaiDAGToDAGISel::selectAddrRr(SDValue Addr, SDValue &R1, SDValue &R2, 240 SDValue &AluOp) { 241 // if Address is FI, get the TargetFrameIndex. 242 if (Addr.getOpcode() == ISD::FrameIndex) 243 return false; 244 245 // Skip direct calls 246 if ((Addr.getOpcode() == ISD::TargetExternalSymbol || 247 Addr.getOpcode() == ISD::TargetGlobalAddress)) 248 return false; 249 250 // Address of the form OP + OP 251 ISD::NodeType AluOperator = static_cast<ISD::NodeType>(Addr.getOpcode()); 252 LPAC::AluCode AluCode = LPAC::isdToLanaiAluCode(AluOperator); 253 if (AluCode != LPAC::UNKNOWN) { 254 // Skip addresses of the form FI OP const 255 if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 256 if (isInt<16>(CN->getSExtValue())) 257 return false; 258 259 // Skip addresses with hi/lo operands 260 if (Addr.getOperand(0).getOpcode() == LanaiISD::HI || 261 Addr.getOperand(0).getOpcode() == LanaiISD::LO || 262 Addr.getOperand(0).getOpcode() == LanaiISD::SMALL || 263 Addr.getOperand(1).getOpcode() == LanaiISD::HI || 264 Addr.getOperand(1).getOpcode() == LanaiISD::LO || 265 Addr.getOperand(1).getOpcode() == LanaiISD::SMALL) 266 return false; 267 268 // Addresses of the form register OP register 269 R1 = Addr.getOperand(0); 270 R2 = Addr.getOperand(1); 271 AluOp = CurDAG->getTargetConstant(AluCode, SDLoc(Addr), MVT::i32); 272 return true; 273 } 274 275 // Skip addresses with zero offset 276 return false; 277 } 278 279 bool LanaiDAGToDAGISel::SelectInlineAsmMemoryOperand( 280 const SDValue &Op, InlineAsm::ConstraintCode ConstraintCode, 281 std::vector<SDValue> &OutOps) { 282 SDValue Op0, Op1, AluOp; 283 switch (ConstraintCode) { 284 default: 285 return true; 286 case InlineAsm::ConstraintCode::m: // memory 287 if (!selectAddrRr(Op, Op0, Op1, AluOp) && 288 !selectAddrRi(Op, Op0, Op1, AluOp)) 289 return true; 290 break; 291 } 292 293 OutOps.push_back(Op0); 294 OutOps.push_back(Op1); 295 OutOps.push_back(AluOp); 296 return false; 297 } 298 299 // Select instructions not customized! Used for 300 // expanded, promoted and normal instructions 301 void LanaiDAGToDAGISel::Select(SDNode *Node) { 302 unsigned Opcode = Node->getOpcode(); 303 304 // If we have a custom node, we already have selected! 305 if (Node->isMachineOpcode()) { 306 LLVM_DEBUG(errs() << "== "; Node->dump(CurDAG); errs() << "\n"); 307 return; 308 } 309 310 // Instruction Selection not handled by the auto-generated tablegen selection 311 // should be handled here. 312 EVT VT = Node->getValueType(0); 313 switch (Opcode) { 314 case ISD::Constant: 315 if (VT == MVT::i32) { 316 ConstantSDNode *ConstNode = cast<ConstantSDNode>(Node); 317 // Materialize zero constants as copies from R0. This allows the coalescer 318 // to propagate these into other instructions. 319 if (ConstNode->isZero()) { 320 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), 321 SDLoc(Node), Lanai::R0, MVT::i32); 322 return ReplaceNode(Node, New.getNode()); 323 } 324 // Materialize all ones constants as copies from R1. This allows the 325 // coalescer to propagate these into other instructions. 326 if (ConstNode->isAllOnes()) { 327 SDValue New = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), 328 SDLoc(Node), Lanai::R1, MVT::i32); 329 return ReplaceNode(Node, New.getNode()); 330 } 331 } 332 break; 333 case ISD::FrameIndex: 334 selectFrameIndex(Node); 335 return; 336 default: 337 break; 338 } 339 340 // Select the default instruction 341 SelectCode(Node); 342 } 343 344 void LanaiDAGToDAGISel::selectFrameIndex(SDNode *Node) { 345 SDLoc DL(Node); 346 SDValue Imm = CurDAG->getTargetConstant(0, DL, MVT::i32); 347 int FI = cast<FrameIndexSDNode>(Node)->getIndex(); 348 EVT VT = Node->getValueType(0); 349 SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT); 350 unsigned Opc = Lanai::ADD_I_LO; 351 if (Node->hasOneUse()) { 352 CurDAG->SelectNodeTo(Node, Opc, VT, TFI, Imm); 353 return; 354 } 355 ReplaceNode(Node, CurDAG->getMachineNode(Opc, DL, VT, TFI, Imm)); 356 } 357 358 // createLanaiISelDag - This pass converts a legalized DAG into a 359 // Lanai-specific DAG, ready for instruction scheduling. 360 FunctionPass *llvm::createLanaiISelDag(LanaiTargetMachine &TM) { 361 return new LanaiDAGToDAGISelLegacy(TM); 362 } 363