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