1 //===- XtensaISelDAGToDAG.cpp - A dag to dag inst selector for Xtensa -----===// 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 Xtensa target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "MCTargetDesc/XtensaMCTargetDesc.h" 14 #include "Xtensa.h" 15 #include "XtensaTargetMachine.h" 16 #include "llvm/CodeGen/MachineFunction.h" 17 #include "llvm/CodeGen/MachineRegisterInfo.h" 18 #include "llvm/CodeGen/SelectionDAGISel.h" 19 #include "llvm/IR/DiagnosticInfo.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/raw_ostream.h" 22 23 using namespace llvm; 24 25 #define DEBUG_TYPE "xtensa-isel" 26 27 namespace { 28 29 class XtensaDAGToDAGISel : public SelectionDAGISel { 30 const XtensaSubtarget *Subtarget = nullptr; 31 32 public: 33 explicit XtensaDAGToDAGISel(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel) 34 : SelectionDAGISel(TM, OptLevel) {} 35 36 bool runOnMachineFunction(MachineFunction &MF) override { 37 Subtarget = &MF.getSubtarget<XtensaSubtarget>(); 38 return SelectionDAGISel::runOnMachineFunction(MF); 39 } 40 41 void Select(SDNode *Node) override; 42 43 bool SelectInlineAsmMemoryOperand(const SDValue &Op, 44 InlineAsm::ConstraintCode ConstraintID, 45 std::vector<SDValue> &OutOps) override; 46 47 // For load/store instructions generate (base+offset) pair from 48 // memory address. The offset must be a multiple of scale argument. 49 bool selectMemRegAddr(SDValue Addr, SDValue &Base, SDValue &Offset, 50 int Scale) { 51 EVT ValTy = Addr.getValueType(); 52 53 // if Address is FI, get the TargetFrameIndex. 54 if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) { 55 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); 56 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), ValTy); 57 58 return true; 59 } 60 61 if (TM.isPositionIndependent()) { 62 DiagnosticInfoUnsupported Diag(CurDAG->getMachineFunction().getFunction(), 63 "PIC relocations are not supported ", 64 Addr.getDebugLoc()); 65 CurDAG->getContext()->diagnose(Diag); 66 } 67 68 if ((Addr.getOpcode() == ISD::TargetExternalSymbol || 69 Addr.getOpcode() == ISD::TargetGlobalAddress)) 70 return false; 71 72 // Addresses of the form FI+const 73 bool Valid = false; 74 if (CurDAG->isBaseWithConstantOffset(Addr)) { 75 ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)); 76 int64_t OffsetVal = CN->getSExtValue(); 77 78 Valid = Xtensa::isValidAddrOffset(Scale, OffsetVal); 79 80 if (Valid) { 81 // If the first operand is a FI, get the TargetFI Node. 82 if (FrameIndexSDNode *FIN = 83 dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) 84 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy); 85 else 86 Base = Addr.getOperand(0); 87 88 Offset = 89 CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr), ValTy); 90 return true; 91 } 92 } 93 94 // Last case 95 Base = Addr; 96 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), Addr.getValueType()); 97 return true; 98 } 99 100 bool selectMemRegAddrISH1(SDValue Addr, SDValue &Base, SDValue &Offset) { 101 return selectMemRegAddr(Addr, Base, Offset, 1); 102 } 103 104 bool selectMemRegAddrISH2(SDValue Addr, SDValue &Base, SDValue &Offset) { 105 return selectMemRegAddr(Addr, Base, Offset, 2); 106 } 107 108 bool selectMemRegAddrISH4(SDValue Addr, SDValue &Base, SDValue &Offset) { 109 return selectMemRegAddr(Addr, Base, Offset, 4); 110 } 111 112 // Include the pieces autogenerated from the target description. 113 #include "XtensaGenDAGISel.inc" 114 }; // namespace 115 116 class XtensaDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 117 public: 118 static char ID; 119 120 XtensaDAGToDAGISelLegacy(XtensaTargetMachine &TM, CodeGenOptLevel OptLevel) 121 : SelectionDAGISelLegacy( 122 ID, std::make_unique<XtensaDAGToDAGISel>(TM, OptLevel)) {} 123 124 StringRef getPassName() const override { 125 return "Xtensa DAG->DAG Pattern Instruction Selection"; 126 } 127 }; 128 } // end anonymous namespace 129 130 char XtensaDAGToDAGISelLegacy::ID = 0; 131 132 FunctionPass *llvm::createXtensaISelDag(XtensaTargetMachine &TM, 133 CodeGenOptLevel OptLevel) { 134 return new XtensaDAGToDAGISelLegacy(TM, OptLevel); 135 } 136 137 void XtensaDAGToDAGISel::Select(SDNode *Node) { 138 SDLoc DL(Node); 139 EVT VT = Node->getValueType(0); 140 141 // If we have a custom node, we already have selected! 142 if (Node->isMachineOpcode()) { 143 Node->setNodeId(-1); 144 return; 145 } 146 147 switch (Node->getOpcode()) { 148 case ISD::SHL: { 149 SDValue N0 = Node->getOperand(0); 150 SDValue N1 = Node->getOperand(1); 151 auto *C = dyn_cast<ConstantSDNode>(N1); 152 // If C is constant in range [1..31] then we can generate SLLI 153 // instruction using pattern matching, otherwise generate SLL. 154 if (!C || C->isZero()) { 155 SDNode *SSL = CurDAG->getMachineNode(Xtensa::SSL, DL, MVT::Glue, N1); 156 SDNode *SLL = 157 CurDAG->getMachineNode(Xtensa::SLL, DL, VT, N0, SDValue(SSL, 0)); 158 ReplaceNode(Node, SLL); 159 return; 160 } 161 break; 162 } 163 case ISD::SRL: { 164 SDValue N0 = Node->getOperand(0); 165 SDValue N1 = Node->getOperand(1); 166 auto *C = dyn_cast<ConstantSDNode>(N1); 167 168 // If C is constant then we can generate SRLI 169 // instruction using pattern matching or EXTUI, otherwise generate SRL. 170 if (C) { 171 if (isUInt<4>(C->getZExtValue())) 172 break; 173 unsigned ShAmt = C->getZExtValue(); 174 SDNode *EXTUI = CurDAG->getMachineNode( 175 Xtensa::EXTUI, DL, VT, N0, CurDAG->getTargetConstant(ShAmt, DL, VT), 176 CurDAG->getTargetConstant(32 - ShAmt, DL, VT)); 177 ReplaceNode(Node, EXTUI); 178 return; 179 } 180 181 SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1); 182 SDNode *SRL = 183 CurDAG->getMachineNode(Xtensa::SRL, DL, VT, N0, SDValue(SSR, 0)); 184 ReplaceNode(Node, SRL); 185 return; 186 } 187 case ISD::SRA: { 188 SDValue N0 = Node->getOperand(0); 189 SDValue N1 = Node->getOperand(1); 190 auto *C = dyn_cast<ConstantSDNode>(N1); 191 // If C is constant then we can generate SRAI 192 // instruction using pattern matching, otherwise generate SRA. 193 if (!C) { 194 SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N1); 195 SDNode *SRA = 196 CurDAG->getMachineNode(Xtensa::SRA, DL, VT, N0, SDValue(SSR, 0)); 197 ReplaceNode(Node, SRA); 198 return; 199 } 200 break; 201 } 202 case XtensaISD::SRCL: { 203 SDValue N0 = Node->getOperand(0); 204 SDValue N1 = Node->getOperand(1); 205 SDValue N2 = Node->getOperand(2); 206 SDNode *SSL = CurDAG->getMachineNode(Xtensa::SSL, DL, MVT::Glue, N2); 207 SDNode *SRC = 208 CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSL, 0)); 209 ReplaceNode(Node, SRC); 210 return; 211 } 212 case XtensaISD::SRCR: { 213 SDValue N0 = Node->getOperand(0); 214 SDValue N1 = Node->getOperand(1); 215 SDValue N2 = Node->getOperand(2); 216 SDNode *SSR = CurDAG->getMachineNode(Xtensa::SSR, DL, MVT::Glue, N2); 217 SDNode *SRC = 218 CurDAG->getMachineNode(Xtensa::SRC, DL, VT, N0, N1, SDValue(SSR, 0)); 219 ReplaceNode(Node, SRC); 220 return; 221 } 222 } 223 224 SelectCode(Node); 225 } 226 227 bool XtensaDAGToDAGISel::SelectInlineAsmMemoryOperand( 228 const SDValue &Op, InlineAsm::ConstraintCode ConstraintID, 229 std::vector<SDValue> &OutOps) { 230 switch (ConstraintID) { 231 default: 232 llvm_unreachable("Unexpected asm memory constraint"); 233 case InlineAsm::ConstraintCode::m: { 234 SDValue Base, Offset; 235 236 selectMemRegAddr(Op, Base, Offset, 4); 237 OutOps.push_back(Base); 238 OutOps.push_back(Offset); 239 240 return false; 241 } 242 } 243 return false; 244 } 245