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