Alex Bradbury | 8971842 | 2017-10-19 21:37:38 +0000 | [diff] [blame] | 1 | //===-- RISCVISelLowering.cpp - RISCV DAG Lowering Implementation --------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file defines the interfaces that RISCV uses to lower LLVM code into a |
| 11 | // selection DAG. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "RISCVISelLowering.h" |
| 16 | #include "RISCV.h" |
| 17 | #include "RISCVRegisterInfo.h" |
| 18 | #include "RISCVSubtarget.h" |
| 19 | #include "RISCVTargetMachine.h" |
| 20 | #include "llvm/CodeGen/CallingConvLower.h" |
| 21 | #include "llvm/CodeGen/MachineFrameInfo.h" |
| 22 | #include "llvm/CodeGen/MachineFunction.h" |
| 23 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
| 24 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
| 25 | #include "llvm/CodeGen/SelectionDAGISel.h" |
| 26 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
| 27 | #include "llvm/CodeGen/ValueTypes.h" |
| 28 | #include "llvm/IR/DiagnosticInfo.h" |
| 29 | #include "llvm/IR/DiagnosticPrinter.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 "riscv-lower" |
| 37 | |
| 38 | RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, |
| 39 | const RISCVSubtarget &STI) |
| 40 | : TargetLowering(TM), Subtarget(STI) { |
| 41 | |
| 42 | MVT XLenVT = Subtarget.getXLenVT(); |
| 43 | |
| 44 | // Set up the register classes. |
| 45 | addRegisterClass(XLenVT, &RISCV::GPRRegClass); |
| 46 | |
| 47 | // Compute derived properties from the register classes. |
| 48 | computeRegisterProperties(STI.getRegisterInfo()); |
| 49 | |
| 50 | setStackPointerRegisterToSaveRestore(RISCV::X2); |
| 51 | |
Alex Bradbury | cfa6291 | 2017-11-08 12:20:01 +0000 | [diff] [blame] | 52 | for (auto N : {ISD::EXTLOAD, ISD::SEXTLOAD, ISD::ZEXTLOAD}) |
| 53 | setLoadExtAction(N, XLenVT, MVT::i1, Promote); |
| 54 | |
Alex Bradbury | 8971842 | 2017-10-19 21:37:38 +0000 | [diff] [blame] | 55 | // TODO: add all necessary setOperationAction calls. |
Alex Bradbury | ec8aa91 | 2017-11-08 13:24:21 +0000 | [diff] [blame^] | 56 | setOperationAction(ISD::GlobalAddress, XLenVT, Custom); |
Alex Bradbury | 8971842 | 2017-10-19 21:37:38 +0000 | [diff] [blame] | 57 | |
| 58 | setBooleanContents(ZeroOrOneBooleanContent); |
| 59 | |
| 60 | // Function alignments (log2). |
| 61 | setMinFunctionAlignment(3); |
| 62 | setPrefFunctionAlignment(3); |
| 63 | } |
| 64 | |
| 65 | SDValue RISCVTargetLowering::LowerOperation(SDValue Op, |
| 66 | SelectionDAG &DAG) const { |
| 67 | switch (Op.getOpcode()) { |
| 68 | default: |
| 69 | report_fatal_error("unimplemented operand"); |
Alex Bradbury | ec8aa91 | 2017-11-08 13:24:21 +0000 | [diff] [blame^] | 70 | case ISD::GlobalAddress: |
| 71 | return lowerGlobalAddress(Op, DAG); |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op, |
| 76 | SelectionDAG &DAG) const { |
| 77 | SDLoc DL(Op); |
| 78 | EVT Ty = Op.getValueType(); |
| 79 | GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); |
| 80 | const GlobalValue *GV = N->getGlobal(); |
| 81 | int64_t Offset = N->getOffset(); |
| 82 | |
| 83 | if (!isPositionIndependent() && !Subtarget.is64Bit()) { |
| 84 | SDValue GAHi = |
| 85 | DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_HI); |
| 86 | SDValue GALo = |
| 87 | DAG.getTargetGlobalAddress(GV, DL, Ty, Offset, RISCVII::MO_LO); |
| 88 | SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0); |
| 89 | SDValue MNLo = |
| 90 | SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0); |
| 91 | return MNLo; |
| 92 | } else { |
| 93 | report_fatal_error("Unable to lowerGlobalAddress"); |
Alex Bradbury | 8971842 | 2017-10-19 21:37:38 +0000 | [diff] [blame] | 94 | } |
| 95 | } |
| 96 | |
| 97 | // Calling Convention Implementation. |
| 98 | #include "RISCVGenCallingConv.inc" |
| 99 | |
| 100 | // Transform physical registers into virtual registers. |
| 101 | SDValue RISCVTargetLowering::LowerFormalArguments( |
| 102 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, |
| 103 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
| 104 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
| 105 | |
| 106 | switch (CallConv) { |
| 107 | default: |
| 108 | report_fatal_error("Unsupported calling convention"); |
| 109 | case CallingConv::C: |
| 110 | break; |
| 111 | } |
| 112 | |
| 113 | MachineFunction &MF = DAG.getMachineFunction(); |
| 114 | MachineRegisterInfo &RegInfo = MF.getRegInfo(); |
| 115 | MVT XLenVT = Subtarget.getXLenVT(); |
| 116 | |
| 117 | if (IsVarArg) |
| 118 | report_fatal_error("VarArg not supported"); |
| 119 | |
| 120 | // Assign locations to all of the incoming arguments. |
| 121 | SmallVector<CCValAssign, 16> ArgLocs; |
| 122 | CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); |
| 123 | CCInfo.AnalyzeFormalArguments(Ins, CC_RISCV32); |
| 124 | |
| 125 | for (auto &VA : ArgLocs) { |
| 126 | if (!VA.isRegLoc()) |
| 127 | report_fatal_error("Defined with too many args"); |
| 128 | |
| 129 | // Arguments passed in registers. |
| 130 | EVT RegVT = VA.getLocVT(); |
| 131 | if (RegVT != XLenVT) { |
| 132 | DEBUG(dbgs() << "LowerFormalArguments Unhandled argument type: " |
| 133 | << RegVT.getEVTString() << "\n"); |
| 134 | report_fatal_error("unhandled argument type"); |
| 135 | } |
| 136 | const unsigned VReg = |
| 137 | RegInfo.createVirtualRegister(&RISCV::GPRRegClass); |
| 138 | RegInfo.addLiveIn(VA.getLocReg(), VReg); |
| 139 | SDValue ArgIn = DAG.getCopyFromReg(Chain, DL, VReg, RegVT); |
| 140 | |
| 141 | InVals.push_back(ArgIn); |
| 142 | } |
| 143 | return Chain; |
| 144 | } |
| 145 | |
| 146 | SDValue |
| 147 | RISCVTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, |
| 148 | bool IsVarArg, |
| 149 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
| 150 | const SmallVectorImpl<SDValue> &OutVals, |
| 151 | const SDLoc &DL, SelectionDAG &DAG) const { |
| 152 | if (IsVarArg) { |
| 153 | report_fatal_error("VarArg not supported"); |
| 154 | } |
| 155 | |
| 156 | // Stores the assignment of the return value to a location. |
| 157 | SmallVector<CCValAssign, 16> RVLocs; |
| 158 | |
| 159 | // Info about the registers and stack slot. |
| 160 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs, |
| 161 | *DAG.getContext()); |
| 162 | |
| 163 | CCInfo.AnalyzeReturn(Outs, RetCC_RISCV32); |
| 164 | |
| 165 | SDValue Flag; |
| 166 | SmallVector<SDValue, 4> RetOps(1, Chain); |
| 167 | |
| 168 | // Copy the result values into the output registers. |
| 169 | for (unsigned i = 0, e = RVLocs.size(); i < e; ++i) { |
| 170 | CCValAssign &VA = RVLocs[i]; |
| 171 | assert(VA.isRegLoc() && "Can only return in registers!"); |
| 172 | |
| 173 | Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); |
| 174 | |
| 175 | // Guarantee that all emitted copies are stuck together. |
| 176 | Flag = Chain.getValue(1); |
| 177 | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); |
| 178 | } |
| 179 | |
| 180 | RetOps[0] = Chain; // Update chain. |
| 181 | |
| 182 | // Add the flag if we have it. |
| 183 | if (Flag.getNode()) { |
| 184 | RetOps.push_back(Flag); |
| 185 | } |
| 186 | |
| 187 | return DAG.getNode(RISCVISD::RET_FLAG, DL, MVT::Other, RetOps); |
| 188 | } |
| 189 | |
| 190 | const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const { |
| 191 | switch ((RISCVISD::NodeType)Opcode) { |
| 192 | case RISCVISD::FIRST_NUMBER: |
| 193 | break; |
| 194 | case RISCVISD::RET_FLAG: |
| 195 | return "RISCVISD::RET_FLAG"; |
| 196 | } |
| 197 | return nullptr; |
| 198 | } |