| Nikolai Bozhenov | 1cf9c54 | 2017-12-07 12:35:02 +0000 | [diff] [blame] | 1 | //===-- Nios2ISelLowering.cpp - Nios2 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 implements the interfaces that Nios2 uses to lower LLVM code into a |
| 11 | // selection DAG. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #include "Nios2ISelLowering.h" |
| 16 | #include "Nios2MachineFunction.h" |
| 17 | #include "Nios2TargetMachine.h" |
| 18 | #include "llvm/CodeGen/CallingConvLower.h" |
| 19 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
| 20 | |
| 21 | using namespace llvm; |
| 22 | |
| 23 | //===----------------------------------------------------------------------===// |
| 24 | // Calling Convention Implementation |
| 25 | //===----------------------------------------------------------------------===// |
| 26 | |
| 27 | #include "Nios2GenCallingConv.inc" |
| 28 | |
| 29 | SDValue |
| 30 | Nios2TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, |
| 31 | bool IsVarArg, |
| 32 | const SmallVectorImpl<ISD::OutputArg> &Outs, |
| 33 | const SmallVectorImpl<SDValue> &OutVals, |
| 34 | const SDLoc &DL, SelectionDAG &DAG) const { |
| Nikolai Bozhenov | eededda | 2018-01-09 11:15:08 +0000 | [diff] [blame] | 35 | // CCValAssign - represent the assignment of |
| 36 | // the return value to a location |
| 37 | SmallVector<CCValAssign, 16> RVLocs; |
| 38 | MachineFunction &MF = DAG.getMachineFunction(); |
| Nikolai Bozhenov | 1cf9c54 | 2017-12-07 12:35:02 +0000 | [diff] [blame] | 39 | |
| Nikolai Bozhenov | eededda | 2018-01-09 11:15:08 +0000 | [diff] [blame] | 40 | // CCState - Info about the registers and stack slot. |
| 41 | CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); |
| 42 | // Analyze return values. |
| 43 | CCInfo.CheckReturn(Outs, RetCC_Nios2EABI); |
| 44 | |
| 45 | SDValue Flag; |
| Nikolai Bozhenov | 1cf9c54 | 2017-12-07 12:35:02 +0000 | [diff] [blame] | 46 | SmallVector<SDValue, 4> RetOps(1, Chain); |
| 47 | |
| Nikolai Bozhenov | eededda | 2018-01-09 11:15:08 +0000 | [diff] [blame] | 48 | // Copy the result values into the output registers. |
| 49 | for (unsigned i = 0; i != RVLocs.size(); ++i) { |
| 50 | SDValue Val = OutVals[i]; |
| 51 | CCValAssign &VA = RVLocs[i]; |
| 52 | assert(VA.isRegLoc() && "Can only return in registers!"); |
| 53 | |
| 54 | if (RVLocs[i].getValVT() != RVLocs[i].getLocVT()) |
| 55 | Val = DAG.getNode(ISD::BITCAST, DL, RVLocs[i].getLocVT(), Val); |
| 56 | |
| 57 | Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Flag); |
| 58 | |
| 59 | // Guarantee that all emitted copies are stuck together with flags. |
| 60 | Flag = Chain.getValue(1); |
| 61 | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); |
| 62 | } |
| 63 | |
| 64 | if (Flag.getNode()) |
| 65 | RetOps.push_back(Flag); |
| 66 | |
| Nikolai Bozhenov | 1cf9c54 | 2017-12-07 12:35:02 +0000 | [diff] [blame] | 67 | return DAG.getNode(Nios2ISD::Ret, DL, MVT::Other, RetOps); |
| 68 | } |
| 69 | |
| 70 | // addLiveIn - This helper function adds the specified physical register to the |
| 71 | // MachineFunction as a live in value. It also creates a corresponding |
| 72 | // virtual register for it. |
| 73 | static unsigned addLiveIn(MachineFunction &MF, unsigned PReg, |
| 74 | const TargetRegisterClass *RC) { |
| 75 | unsigned VReg = MF.getRegInfo().createVirtualRegister(RC); |
| 76 | MF.getRegInfo().addLiveIn(PReg, VReg); |
| 77 | return VReg; |
| 78 | } |
| 79 | |
| 80 | //===----------------------------------------------------------------------===// |
| 81 | // Formal Arguments Calling Convention Implementation |
| 82 | //===----------------------------------------------------------------------===// |
| 83 | |
| 84 | // LowerFormalArguments - transform physical registers into virtual registers |
| 85 | // and generate load operations for arguments places on the stack. |
| 86 | SDValue Nios2TargetLowering::LowerFormalArguments( |
| 87 | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, |
| 88 | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, |
| 89 | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { |
| 90 | MachineFunction &MF = DAG.getMachineFunction(); |
| 91 | MachineFrameInfo &MFI = MF.getFrameInfo(); |
| 92 | |
| 93 | // Assign locations to all of the incoming arguments. |
| 94 | SmallVector<CCValAssign, 16> ArgLocs; |
| 95 | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, |
| 96 | *DAG.getContext()); |
| 97 | |
| 98 | CCInfo.AnalyzeFormalArguments(Ins, CC_Nios2); |
| 99 | |
| 100 | // Used with vargs to acumulate store chains. |
| 101 | std::vector<SDValue> OutChains; |
| 102 | |
| 103 | for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { |
| 104 | CCValAssign &VA = ArgLocs[i]; |
| 105 | |
| 106 | EVT ValVT = VA.getValVT(); |
| 107 | |
| 108 | // Arguments stored on registers |
| 109 | if (VA.isRegLoc()) { |
| 110 | MVT RegVT = VA.getLocVT(); |
| 111 | unsigned ArgReg = VA.getLocReg(); |
| 112 | const TargetRegisterClass *RC = getRegClassFor(RegVT); |
| 113 | |
| 114 | // Transform the arguments stored on |
| 115 | // physical registers into virtual ones |
| 116 | unsigned Reg = addLiveIn(MF, ArgReg, RC); |
| 117 | SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, RegVT); |
| 118 | |
| 119 | // If this is an 8 or 16-bit value, it has been passed promoted |
| 120 | // to 32 bits. Insert an assert[sz]ext to capture this, then |
| 121 | // truncate to the right size. |
| 122 | if (VA.getLocInfo() != CCValAssign::Full) { |
| 123 | unsigned Opcode = 0; |
| 124 | if (VA.getLocInfo() == CCValAssign::SExt) |
| 125 | Opcode = ISD::AssertSext; |
| 126 | else if (VA.getLocInfo() == CCValAssign::ZExt) |
| 127 | Opcode = ISD::AssertZext; |
| 128 | if (Opcode) |
| 129 | ArgValue = |
| 130 | DAG.getNode(Opcode, DL, RegVT, ArgValue, DAG.getValueType(ValVT)); |
| 131 | ArgValue = DAG.getNode(ISD::TRUNCATE, DL, ValVT, ArgValue); |
| 132 | } |
| 133 | |
| 134 | // Handle floating point arguments passed in integer registers. |
| 135 | if ((RegVT == MVT::i32 && ValVT == MVT::f32) || |
| 136 | (RegVT == MVT::i64 && ValVT == MVT::f64)) |
| 137 | ArgValue = DAG.getNode(ISD::BITCAST, DL, ValVT, ArgValue); |
| 138 | InVals.push_back(ArgValue); |
| 139 | } else { // VA.isRegLoc() |
| 140 | MVT LocVT = VA.getLocVT(); |
| 141 | |
| 142 | // sanity check |
| 143 | assert(VA.isMemLoc()); |
| 144 | |
| 145 | // The stack pointer offset is relative to the caller stack frame. |
| 146 | int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, |
| 147 | VA.getLocMemOffset(), true); |
| 148 | |
| 149 | // Create load nodes to retrieve arguments from the stack |
| 150 | SDValue FIN = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); |
| 151 | SDValue Load = DAG.getLoad( |
| 152 | LocVT, DL, Chain, FIN, |
| 153 | MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI)); |
| 154 | InVals.push_back(Load); |
| 155 | OutChains.push_back(Load.getValue(1)); |
| 156 | } |
| 157 | } |
| 158 | if (!OutChains.empty()) { |
| 159 | OutChains.push_back(Chain); |
| 160 | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); |
| 161 | } |
| 162 | |
| 163 | return Chain; |
| 164 | } |
| 165 | |
| 166 | //===----------------------------------------------------------------------===// |
| 167 | // TargetLowering Implementation |
| 168 | //===----------------------------------------------------------------------===// |
| 169 | |
| 170 | Nios2TargetLowering::Nios2TargetLowering(const TargetMachine &TM, |
| 171 | const Nios2Subtarget &STI) |
| 172 | : TargetLowering(TM), Subtarget(&STI) { |
| 173 | |
| 174 | addRegisterClass(MVT::i32, &Nios2::CPURegsRegClass); |
| 175 | computeRegisterProperties(Subtarget->getRegisterInfo()); |
| 176 | } |
| 177 | |
| 178 | const char *Nios2TargetLowering::getTargetNodeName(unsigned Opcode) const { |
| 179 | switch (Opcode) { |
| 180 | case Nios2ISD::Hi: |
| 181 | return "Nios2ISD::Hi"; |
| 182 | case Nios2ISD::Lo: |
| 183 | return "Nios2ISD::Lo"; |
| 184 | case Nios2ISD::Ret: |
| 185 | return "Nios2ISD::Ret"; |
| 186 | } |
| 187 | return nullptr; |
| 188 | } |