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