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