1 //===- ARCISelDAGToDAG.cpp - ARC dag to dag inst selector -------*- C++ -*-===// 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 ARC target. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "ARC.h" 14 #include "ARCTargetMachine.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/LLVMContext.h" 28 #include "llvm/Support/Compiler.h" 29 #include "llvm/Support/Debug.h" 30 #include "llvm/Support/ErrorHandling.h" 31 #include "llvm/Support/raw_ostream.h" 32 33 using namespace llvm; 34 35 #define DEBUG_TYPE "arc-isel" 36 #define PASS_NAME "ARC DAG->DAG Pattern Instruction Selection" 37 38 /// ARCDAGToDAGISel - ARC specific code to select ARC machine 39 /// instructions for SelectionDAG operations. 40 namespace { 41 42 class ARCDAGToDAGISel : public SelectionDAGISel { 43 public: 44 ARCDAGToDAGISel() = delete; 45 46 ARCDAGToDAGISel(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) 47 : SelectionDAGISel(TM, OptLevel) {} 48 49 void Select(SDNode *N) override; 50 51 // Complex Pattern Selectors. 52 bool SelectFrameADDR_ri(SDValue Addr, SDValue &Base, SDValue &Offset); 53 bool SelectAddrModeS9(SDValue Addr, SDValue &Base, SDValue &Offset); 54 bool SelectAddrModeImm(SDValue Addr, SDValue &Base, SDValue &Offset); 55 bool SelectAddrModeFar(SDValue Addr, SDValue &Base, SDValue &Offset); 56 57 // Include the pieces autogenerated from the target description. 58 #include "ARCGenDAGISel.inc" 59 }; 60 61 class ARCDAGToDAGISelLegacy : public SelectionDAGISelLegacy { 62 public: 63 static char ID; 64 explicit ARCDAGToDAGISelLegacy(ARCTargetMachine &TM, CodeGenOptLevel OptLevel) 65 : SelectionDAGISelLegacy( 66 ID, std::make_unique<ARCDAGToDAGISel>(TM, OptLevel)) {} 67 }; 68 69 char ARCDAGToDAGISelLegacy::ID; 70 71 } // end anonymous namespace 72 73 INITIALIZE_PASS(ARCDAGToDAGISelLegacy, DEBUG_TYPE, PASS_NAME, false, false) 74 75 /// This pass converts a legalized DAG into a ARC-specific DAG, ready for 76 /// instruction scheduling. 77 FunctionPass *llvm::createARCISelDag(ARCTargetMachine &TM, 78 CodeGenOptLevel OptLevel) { 79 return new ARCDAGToDAGISelLegacy(TM, OptLevel); 80 } 81 82 bool ARCDAGToDAGISel::SelectAddrModeImm(SDValue Addr, SDValue &Base, 83 SDValue &Offset) { 84 if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 85 Base = Addr.getOperand(0); 86 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 87 return true; 88 } 89 return false; 90 } 91 92 bool ARCDAGToDAGISel::SelectAddrModeS9(SDValue Addr, SDValue &Base, 93 SDValue &Offset) { 94 if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 95 return false; 96 } 97 98 if (Addr.getOpcode() != ISD::ADD && Addr.getOpcode() != ISD::SUB && 99 !CurDAG->isBaseWithConstantOffset(Addr)) { 100 if (Addr.getOpcode() == ISD::FrameIndex) { 101 // Match frame index. 102 int FI = cast<FrameIndexSDNode>(Addr)->getIndex(); 103 Base = CurDAG->getTargetFrameIndex( 104 FI, TLI->getPointerTy(CurDAG->getDataLayout())); 105 } else { 106 Base = Addr; 107 } 108 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 109 return true; 110 } 111 112 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 113 int32_t RHSC = RHS->getSExtValue(); 114 if (Addr.getOpcode() == ISD::SUB) 115 RHSC = -RHSC; 116 117 // Do we need more than 9 bits to encode? 118 if (!isInt<9>(RHSC)) 119 return false; 120 Base = Addr.getOperand(0); 121 if (Base.getOpcode() == ISD::FrameIndex) { 122 int FI = cast<FrameIndexSDNode>(Base)->getIndex(); 123 Base = CurDAG->getTargetFrameIndex( 124 FI, TLI->getPointerTy(CurDAG->getDataLayout())); 125 } 126 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 127 return true; 128 } 129 Base = Addr; 130 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 131 return true; 132 } 133 134 bool ARCDAGToDAGISel::SelectAddrModeFar(SDValue Addr, SDValue &Base, 135 SDValue &Offset) { 136 if (SelectAddrModeS9(Addr, Base, Offset)) 137 return false; 138 if (Addr.getOpcode() == ARCISD::GAWRAPPER) { 139 return false; 140 } 141 if (ConstantSDNode *RHS = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) { 142 int32_t RHSC = RHS->getSExtValue(); 143 if (Addr.getOpcode() == ISD::SUB) 144 RHSC = -RHSC; 145 Base = Addr.getOperand(0); 146 Offset = CurDAG->getTargetConstant(RHSC, SDLoc(Addr), MVT::i32); 147 return true; 148 } 149 return false; 150 } 151 152 // Is this a legal frame index addressing expression. 153 bool ARCDAGToDAGISel::SelectFrameADDR_ri(SDValue Addr, SDValue &Base, 154 SDValue &Offset) { 155 FrameIndexSDNode *FIN = nullptr; 156 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr))) { 157 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 158 Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); 159 return true; 160 } 161 if (Addr.getOpcode() == ISD::ADD) { 162 ConstantSDNode *CN = nullptr; 163 if ((FIN = dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) && 164 (CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) && 165 (CN->getSExtValue() % 4 == 0 && CN->getSExtValue() >= 0)) { 166 // Constant positive word offset from frame index 167 Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); 168 Offset = 169 CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); 170 return true; 171 } 172 } 173 return false; 174 } 175 176 void ARCDAGToDAGISel::Select(SDNode *N) { 177 switch (N->getOpcode()) { 178 case ISD::Constant: { 179 uint64_t CVal = N->getAsZExtVal(); 180 ReplaceNode(N, CurDAG->getMachineNode( 181 isInt<12>(CVal) ? ARC::MOV_rs12 : ARC::MOV_rlimm, 182 SDLoc(N), MVT::i32, 183 CurDAG->getTargetConstant(CVal, SDLoc(N), MVT::i32))); 184 return; 185 } 186 } 187 SelectCode(N); 188 } 189