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