1 //===-- XCoreISelDAGToDAG.cpp - A dag to dag inst selector for XCore ------===// 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 XCore target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "XCore.h" 14 #include "XCoreTargetMachine.h" 15 #include "llvm/CodeGen/MachineFrameInfo.h" 16 #include "llvm/CodeGen/MachineFunction.h" 17 #include "llvm/CodeGen/MachineInstrBuilder.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/CodeGen/SelectionDAG.h" 20 #include "llvm/CodeGen/SelectionDAGISel.h" 21 #include "llvm/CodeGen/TargetLowering.h" 22 #include "llvm/IR/CallingConv.h" 23 #include "llvm/IR/Constants.h" 24 #include "llvm/IR/DerivedTypes.h" 25 #include "llvm/IR/Function.h" 26 #include "llvm/IR/Intrinsics.h" 27 #include "llvm/IR/IntrinsicsXCore.h" 28 #include "llvm/IR/LLVMContext.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/ErrorHandling.h" 31 #include "llvm/Support/raw_ostream.h" 32 using namespace llvm; 33 34 #define DEBUG_TYPE "xcore-isel" 35 #define PASS_NAME "XCore DAG->DAG Pattern Instruction Selection" 36 37 /// XCoreDAGToDAGISel - XCore specific code to select XCore machine 38 /// instructions for SelectionDAG operations. 39 /// 40 namespace { 41 class XCoreDAGToDAGISel : public SelectionDAGISel { 42 43 public: 44 static char ID; 45 46 XCoreDAGToDAGISel() = delete; 47 48 XCoreDAGToDAGISel(XCoreTargetMachine &TM, CodeGenOpt::Level OptLevel) 49 : SelectionDAGISel(ID, TM, OptLevel) {} 50 51 void Select(SDNode *N) override; 52 bool tryBRIND(SDNode *N); 53 54 /// getI32Imm - Return a target constant with the specified value, of type 55 /// i32. 56 inline SDValue getI32Imm(unsigned Imm, const SDLoc &dl) { 57 return CurDAG->getTargetConstant(Imm, dl, MVT::i32); 58 } 59 60 inline bool immMskBitp(SDNode *inN) const { 61 ConstantSDNode *N = cast<ConstantSDNode>(inN); 62 uint32_t value = (uint32_t)N->getZExtValue(); 63 if (!isMask_32(value)) { 64 return false; 65 } 66 int msksize = llvm::bit_width(value); 67 return (msksize >= 1 && msksize <= 8) || 68 msksize == 16 || msksize == 24 || msksize == 32; 69 } 70 71 // Complex Pattern Selectors. 72 bool SelectADDRspii(SDValue Addr, SDValue &Base, SDValue &Offset); 73 74 bool SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 75 std::vector<SDValue> &OutOps) override; 76 77 // Include the pieces autogenerated from the target description. 78 #include "XCoreGenDAGISel.inc" 79 }; 80 } // end anonymous namespace 81 82 char XCoreDAGToDAGISel::ID = 0; 83 84 INITIALIZE_PASS(XCoreDAGToDAGISel, DEBUG_TYPE, PASS_NAME, false, false) 85 86 /// createXCoreISelDag - This pass converts a legalized DAG into a 87 /// XCore-specific DAG, ready for instruction scheduling. 88 /// 89 FunctionPass *llvm::createXCoreISelDag(XCoreTargetMachine &TM, 90 CodeGenOpt::Level OptLevel) { 91 return new XCoreDAGToDAGISel(TM, OptLevel); 92 } 93 94 bool XCoreDAGToDAGISel::SelectADDRspii(SDValue Addr, SDValue &Base, 95 SDValue &Offset) { 96 FrameIndexSDNode *FIN = nullptr; 97 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { 98 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 99 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 100 return true; 101 } 102 if (Addr.getOpcode() == ISD::ADD) { 103 ConstantSDNode *CN = nullptr; 104 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) 105 && (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) 106 && (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { 107 // Constant positive word offset from frame index 108 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 109 Offset = CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), 110 MVT::i32); 111 return true; 112 } 113 } 114 return false; 115 } 116 117 bool XCoreDAGToDAGISel:: 118 SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, 119 std::vector<SDValue> &OutOps) { 120 SDValue Reg; 121 switch (ConstraintID) { 122 default: return true; 123 case InlineAsm::Constraint_m: // Memory. 124 switch (Op.getOpcode()) { 125 default: return true; 126 case XCoreISD::CPRelativeWrapper: 127 Reg = CurDAG->getRegister(XCore::CP, MVT::i32); 128 break; 129 case XCoreISD::DPRelativeWrapper: 130 Reg = CurDAG->getRegister(XCore::DP, MVT::i32); 131 break; 132 } 133 } 134 OutOps.push_back(Reg); 135 OutOps.push_back(Op.getOperand(0)); 136 return false; 137 } 138 139 void XCoreDAGToDAGISel::Select(SDNode *N) { 140 SDLoc dl(N); 141 switch (N->getOpcode()) { 142 default: break; 143 case ISD::Constant: { 144 uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue(); 145 if (immMskBitp(N)) { 146 // Transformation function: get the size of a mask 147 // Look for the first non-zero bit 148 SDValue MskSize = getI32Imm(llvm::bit_width((uint32_t)Val), dl); 149 ReplaceNode( 150 N, CurDAG->getMachineNode(XCore::MKMSK_rus, dl, MVT::i32, MskSize)); 151 return; 152 } 153 else if (!isUInt<16>(Val)) { 154 SDValue CPIdx = CurDAG->getTargetConstantPool( 155 ConstantInt::get(Type::getInt32Ty(*CurDAG->getContext()), Val), 156 getTargetLowering()->getPointerTy(CurDAG->getDataLayout())); 157 SDNode *node = CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32, 158 MVT::Other, CPIdx, 159 CurDAG->getEntryNode()); 160 MachineMemOperand *MemOp = 161 MF->getMachineMemOperand(MachinePointerInfo::getConstantPool(*MF), 162 MachineMemOperand::MOLoad, 4, Align(4)); 163 CurDAG->setNodeMemRefs(cast<MachineSDNode>(node), {MemOp}); 164 ReplaceNode(N, node); 165 return; 166 } 167 break; 168 } 169 case XCoreISD::LADD: { 170 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 171 N->getOperand(2) }; 172 ReplaceNode(N, CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, 173 MVT::i32, Ops)); 174 return; 175 } 176 case XCoreISD::LSUB: { 177 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 178 N->getOperand(2) }; 179 ReplaceNode(N, CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, 180 MVT::i32, Ops)); 181 return; 182 } 183 case XCoreISD::MACCU: { 184 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 185 N->getOperand(2), N->getOperand(3) }; 186 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, 187 MVT::i32, Ops)); 188 return; 189 } 190 case XCoreISD::MACCS: { 191 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 192 N->getOperand(2), N->getOperand(3) }; 193 ReplaceNode(N, CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, 194 MVT::i32, Ops)); 195 return; 196 } 197 case XCoreISD::LMUL: { 198 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), 199 N->getOperand(2), N->getOperand(3) }; 200 ReplaceNode(N, CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, 201 MVT::i32, Ops)); 202 return; 203 } 204 case XCoreISD::CRC8: { 205 SDValue Ops[] = { N->getOperand(0), N->getOperand(1), N->getOperand(2) }; 206 ReplaceNode(N, CurDAG->getMachineNode(XCore::CRC8_l4r, dl, MVT::i32, 207 MVT::i32, Ops)); 208 return; 209 } 210 case ISD::BRIND: 211 if (tryBRIND(N)) 212 return; 213 break; 214 // Other cases are autogenerated. 215 } 216 SelectCode(N); 217 } 218 219 /// Given a chain return a new chain where any appearance of Old is replaced 220 /// by New. There must be at most one instruction between Old and Chain and 221 /// this instruction must be a TokenFactor. Returns an empty SDValue if 222 /// these conditions don't hold. 223 static SDValue 224 replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New) 225 { 226 if (Chain == Old) 227 return New; 228 if (Chain->getOpcode() != ISD::TokenFactor) 229 return SDValue(); 230 SmallVector<SDValue, 8> Ops; 231 bool found = false; 232 for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) { 233 if (Chain->getOperand(i) == Old) { 234 Ops.push_back(New); 235 found = true; 236 } else { 237 Ops.push_back(Chain->getOperand(i)); 238 } 239 } 240 if (!found) 241 return SDValue(); 242 return CurDAG->getNode(ISD::TokenFactor, SDLoc(Chain), MVT::Other, Ops); 243 } 244 245 bool XCoreDAGToDAGISel::tryBRIND(SDNode *N) { 246 SDLoc dl(N); 247 // (brind (int_xcore_checkevent (addr))) 248 SDValue Chain = N->getOperand(0); 249 SDValue Addr = N->getOperand(1); 250 if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN) 251 return false; 252 unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue(); 253 if (IntNo != Intrinsic::xcore_checkevent) 254 return false; 255 SDValue nextAddr = Addr->getOperand(2); 256 SDValue CheckEventChainOut(Addr.getNode(), 1); 257 if (!CheckEventChainOut.use_empty()) { 258 // If the chain out of the checkevent intrinsic is an operand of the 259 // indirect branch or used in a TokenFactor which is the operand of the 260 // indirect branch then build a new chain which uses the chain coming into 261 // the checkevent intrinsic instead. 262 SDValue CheckEventChainIn = Addr->getOperand(0); 263 SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut, 264 CheckEventChainIn); 265 if (!NewChain.getNode()) 266 return false; 267 Chain = NewChain; 268 } 269 // Enable events on the thread using setsr 1 and then disable them immediately 270 // after with clrsr 1. If any resources owned by the thread are ready an event 271 // will be taken. If no resource is ready we branch to the address which was 272 // the operand to the checkevent intrinsic. 273 SDValue constOne = getI32Imm(1, dl); 274 SDValue Glue = 275 SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue, 276 constOne, Chain), 0); 277 Glue = 278 SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue, 279 constOne, Glue), 0); 280 if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper && 281 nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) { 282 CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other, 283 nextAddr->getOperand(0), Glue); 284 return true; 285 } 286 CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue); 287 return true; 288 } 289