|  | //===-- CSKYISelLowering.cpp - CSKY DAG Lowering Implementation  ----------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines the interfaces that CSKY uses to lower LLVM code into a | 
|  | // selection DAG. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "CSKYISelLowering.h" | 
|  | #include "CSKYCallingConv.h" | 
|  | #include "CSKYConstantPoolValue.h" | 
|  | #include "CSKYMachineFunctionInfo.h" | 
|  | #include "CSKYRegisterInfo.h" | 
|  | #include "CSKYSubtarget.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/CodeGen/CallingConvLower.h" | 
|  | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | #include "llvm/CodeGen/MachineJumpTableInfo.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "csky-isel-lowering" | 
|  |  | 
|  | STATISTIC(NumTailCalls, "Number of tail calls"); | 
|  |  | 
|  | #include "CSKYGenCallingConv.inc" | 
|  |  | 
|  | static const MCPhysReg GPRArgRegs[] = {CSKY::R0, CSKY::R1, CSKY::R2, CSKY::R3}; | 
|  |  | 
|  | CSKYTargetLowering::CSKYTargetLowering(const TargetMachine &TM, | 
|  | const CSKYSubtarget &STI) | 
|  | : TargetLowering(TM), Subtarget(STI) { | 
|  | // Register Class | 
|  | addRegisterClass(MVT::i32, &CSKY::GPRRegClass); | 
|  |  | 
|  | if (STI.useHardFloat()) { | 
|  | if (STI.hasFPUv2SingleFloat()) | 
|  | addRegisterClass(MVT::f32, &CSKY::sFPR32RegClass); | 
|  | else if (STI.hasFPUv3SingleFloat()) | 
|  | addRegisterClass(MVT::f32, &CSKY::FPR32RegClass); | 
|  |  | 
|  | if (STI.hasFPUv2DoubleFloat()) | 
|  | addRegisterClass(MVT::f64, &CSKY::sFPR64RegClass); | 
|  | else if (STI.hasFPUv3DoubleFloat()) | 
|  | addRegisterClass(MVT::f64, &CSKY::FPR64RegClass); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::UADDO_CARRY, MVT::i32, Legal); | 
|  | setOperationAction(ISD::USUBO_CARRY, MVT::i32, Legal); | 
|  | setOperationAction(ISD::BITREVERSE, MVT::i32, Legal); | 
|  |  | 
|  | setOperationAction(ISD::SREM, MVT::i32, Expand); | 
|  | setOperationAction(ISD::UREM, MVT::i32, Expand); | 
|  | setOperationAction(ISD::UDIVREM, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SDIVREM, MVT::i32, Expand); | 
|  | setOperationAction(ISD::CTPOP, MVT::i32, Expand); | 
|  | setOperationAction(ISD::ROTR, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SELECT_CC, MVT::i32, Expand); | 
|  | setOperationAction(ISD::BR_CC, MVT::i32, Expand); | 
|  | setOperationAction(ISD::BR_JT, MVT::Other, Expand); | 
|  | setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Expand); | 
|  | setOperationAction(ISD::STACKSAVE, MVT::Other, Expand); | 
|  | setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand); | 
|  | setOperationAction(ISD::MULHS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::MULHU, MVT::i32, Expand); | 
|  | setOperationAction(ISD::VAARG, MVT::Other, Expand); | 
|  | setOperationAction(ISD::VACOPY, MVT::Other, Expand); | 
|  | setOperationAction(ISD::VAEND, MVT::Other, Expand); | 
|  |  | 
|  | setLoadExtAction(ISD::EXTLOAD, MVT::i32, MVT::i1, Promote); | 
|  | setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i1, Promote); | 
|  | setLoadExtAction(ISD::ZEXTLOAD, MVT::i32, MVT::i1, Promote); | 
|  |  | 
|  | setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); | 
|  | setOperationAction(ISD::ExternalSymbol, MVT::i32, Custom); | 
|  | setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom); | 
|  | setOperationAction(ISD::BlockAddress, MVT::i32, Custom); | 
|  | if (!Subtarget.hasE2()) { | 
|  | setOperationAction(ISD::ConstantPool, MVT::i32, Custom); | 
|  | } | 
|  | setOperationAction(ISD::JumpTable, MVT::i32, Custom); | 
|  | setOperationAction(ISD::VASTART, MVT::Other, Custom); | 
|  |  | 
|  | if (!Subtarget.hasE2()) { | 
|  | setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i8, Expand); | 
|  | setLoadExtAction(ISD::SEXTLOAD, MVT::i32, MVT::i16, Expand); | 
|  | setOperationAction(ISD::CTLZ, MVT::i32, Expand); | 
|  | setOperationAction(ISD::BSWAP, MVT::i32, Expand); | 
|  | } | 
|  |  | 
|  | if (!Subtarget.has2E3()) { | 
|  | setOperationAction(ISD::ABS, MVT::i32, Expand); | 
|  | setOperationAction(ISD::BITREVERSE, MVT::i32, Expand); | 
|  | setOperationAction(ISD::CTTZ, MVT::i32, Expand); | 
|  | setOperationAction(ISD::SDIV, MVT::i32, Expand); | 
|  | setOperationAction(ISD::UDIV, MVT::i32, Expand); | 
|  | } | 
|  |  | 
|  | setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand); | 
|  |  | 
|  | // Float | 
|  |  | 
|  | ISD::CondCode FPCCToExtend[] = { | 
|  | ISD::SETONE, ISD::SETUEQ, ISD::SETUGT, | 
|  | ISD::SETUGE, ISD::SETULT, ISD::SETULE, | 
|  | }; | 
|  |  | 
|  | ISD::NodeType FPOpToExpand[] = { | 
|  | ISD::FSIN, ISD::FCOS,      ISD::FSINCOS,    ISD::FPOW, | 
|  | ISD::FREM, ISD::FCOPYSIGN, ISD::FP16_TO_FP, ISD::FP_TO_FP16}; | 
|  |  | 
|  | if (STI.useHardFloat()) { | 
|  |  | 
|  | MVT AllVTy[] = {MVT::f32, MVT::f64}; | 
|  |  | 
|  | for (auto VT : AllVTy) { | 
|  | setOperationAction(ISD::FREM, VT, Expand); | 
|  | setOperationAction(ISD::SELECT_CC, VT, Expand); | 
|  | setOperationAction(ISD::BR_CC, VT, Expand); | 
|  |  | 
|  | for (auto CC : FPCCToExtend) | 
|  | setCondCodeAction(CC, VT, Expand); | 
|  | for (auto Op : FPOpToExpand) | 
|  | setOperationAction(Op, VT, Expand); | 
|  | } | 
|  |  | 
|  | if (STI.hasFPUv2SingleFloat() || STI.hasFPUv3SingleFloat()) { | 
|  | setOperationAction(ISD::ConstantFP, MVT::f32, Legal); | 
|  | setLoadExtAction(ISD::EXTLOAD, MVT::f32, MVT::f16, Expand); | 
|  | setTruncStoreAction(MVT::f32, MVT::f16, Expand); | 
|  | } | 
|  | if (STI.hasFPUv2DoubleFloat() || STI.hasFPUv3DoubleFloat()) { | 
|  | setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f32, Expand); | 
|  | setTruncStoreAction(MVT::f64, MVT::f32, Expand); | 
|  | setLoadExtAction(ISD::EXTLOAD, MVT::f64, MVT::f16, Expand); | 
|  | setTruncStoreAction(MVT::f64, MVT::f16, Expand); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Compute derived properties from the register classes. | 
|  | computeRegisterProperties(STI.getRegisterInfo()); | 
|  |  | 
|  | setBooleanContents(UndefinedBooleanContent); | 
|  | setBooleanVectorContents(ZeroOrNegativeOneBooleanContent); | 
|  |  | 
|  | // TODO: Add atomic support fully. | 
|  | setMaxAtomicSizeInBitsSupported(0); | 
|  |  | 
|  | setStackPointerRegisterToSaveRestore(CSKY::R14); | 
|  | setMinFunctionAlignment(Align(2)); | 
|  | setSchedulingPreference(Sched::Source); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerOperation(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | switch (Op.getOpcode()) { | 
|  | default: | 
|  | llvm_unreachable("unimplemented op"); | 
|  | case ISD::GlobalAddress: | 
|  | return LowerGlobalAddress(Op, DAG); | 
|  | case ISD::ExternalSymbol: | 
|  | return LowerExternalSymbol(Op, DAG); | 
|  | case ISD::GlobalTLSAddress: | 
|  | return LowerGlobalTLSAddress(Op, DAG); | 
|  | case ISD::JumpTable: | 
|  | return LowerJumpTable(Op, DAG); | 
|  | case ISD::BlockAddress: | 
|  | return LowerBlockAddress(Op, DAG); | 
|  | case ISD::ConstantPool: | 
|  | return LowerConstantPool(Op, DAG); | 
|  | case ISD::VASTART: | 
|  | return LowerVASTART(Op, DAG); | 
|  | case ISD::FRAMEADDR: | 
|  | return LowerFRAMEADDR(Op, DAG); | 
|  | case ISD::RETURNADDR: | 
|  | return LowerRETURNADDR(Op, DAG); | 
|  | } | 
|  | } | 
|  |  | 
|  | EVT CSKYTargetLowering::getSetCCResultType(const DataLayout &DL, | 
|  | LLVMContext &Context, EVT VT) const { | 
|  | if (!VT.isVector()) | 
|  | return MVT::i32; | 
|  |  | 
|  | return VT.changeVectorElementTypeToInteger(); | 
|  | } | 
|  |  | 
|  | static SDValue convertValVTToLocVT(SelectionDAG &DAG, SDValue Val, | 
|  | const CCValAssign &VA, const SDLoc &DL) { | 
|  | EVT LocVT = VA.getLocVT(); | 
|  |  | 
|  | switch (VA.getLocInfo()) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected CCValAssign::LocInfo"); | 
|  | case CCValAssign::Full: | 
|  | break; | 
|  | case CCValAssign::BCvt: | 
|  | Val = DAG.getNode(ISD::BITCAST, DL, LocVT, Val); | 
|  | break; | 
|  | } | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | static SDValue convertLocVTToValVT(SelectionDAG &DAG, SDValue Val, | 
|  | const CCValAssign &VA, const SDLoc &DL) { | 
|  | switch (VA.getLocInfo()) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected CCValAssign::LocInfo"); | 
|  | case CCValAssign::Full: | 
|  | break; | 
|  | case CCValAssign::BCvt: | 
|  | Val = DAG.getNode(ISD::BITCAST, DL, VA.getValVT(), Val); | 
|  | break; | 
|  | } | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | static SDValue unpackFromRegLoc(const CSKYSubtarget &Subtarget, | 
|  | SelectionDAG &DAG, SDValue Chain, | 
|  | const CCValAssign &VA, const SDLoc &DL) { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineRegisterInfo &RegInfo = MF.getRegInfo(); | 
|  | EVT LocVT = VA.getLocVT(); | 
|  | SDValue Val; | 
|  | const TargetRegisterClass *RC; | 
|  |  | 
|  | switch (LocVT.getSimpleVT().SimpleTy) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected register type"); | 
|  | case MVT::i32: | 
|  | RC = &CSKY::GPRRegClass; | 
|  | break; | 
|  | case MVT::f32: | 
|  | RC = Subtarget.hasFPUv2SingleFloat() ? &CSKY::sFPR32RegClass | 
|  | : &CSKY::FPR32RegClass; | 
|  | break; | 
|  | case MVT::f64: | 
|  | RC = Subtarget.hasFPUv2DoubleFloat() ? &CSKY::sFPR64RegClass | 
|  | : &CSKY::FPR64RegClass; | 
|  | break; | 
|  | } | 
|  |  | 
|  | Register VReg = RegInfo.createVirtualRegister(RC); | 
|  | RegInfo.addLiveIn(VA.getLocReg(), VReg); | 
|  | Val = DAG.getCopyFromReg(Chain, DL, VReg, LocVT); | 
|  |  | 
|  | return convertLocVTToValVT(DAG, Val, VA, DL); | 
|  | } | 
|  |  | 
|  | static SDValue unpackFromMemLoc(SelectionDAG &DAG, SDValue Chain, | 
|  | const CCValAssign &VA, const SDLoc &DL) { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | EVT LocVT = VA.getLocVT(); | 
|  | EVT ValVT = VA.getValVT(); | 
|  | EVT PtrVT = MVT::getIntegerVT(DAG.getDataLayout().getPointerSizeInBits(0)); | 
|  | int FI = MFI.CreateFixedObject(ValVT.getSizeInBits() / 8, | 
|  | VA.getLocMemOffset(), /*Immutable=*/true); | 
|  | SDValue FIN = DAG.getFrameIndex(FI, PtrVT); | 
|  | SDValue Val; | 
|  |  | 
|  | ISD::LoadExtType ExtType; | 
|  | switch (VA.getLocInfo()) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected CCValAssign::LocInfo"); | 
|  | case CCValAssign::Full: | 
|  | case CCValAssign::BCvt: | 
|  | ExtType = ISD::NON_EXTLOAD; | 
|  | break; | 
|  | } | 
|  | Val = DAG.getExtLoad( | 
|  | ExtType, DL, LocVT, Chain, FIN, | 
|  | MachinePointerInfo::getFixedStack(DAG.getMachineFunction(), FI), ValVT); | 
|  | return Val; | 
|  | } | 
|  |  | 
|  | static SDValue unpack64(SelectionDAG &DAG, SDValue Chain, const CCValAssign &VA, | 
|  | const SDLoc &DL) { | 
|  | assert(VA.getLocVT() == MVT::i32 && | 
|  | (VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::i64) && | 
|  | "Unexpected VA"); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MachineRegisterInfo &RegInfo = MF.getRegInfo(); | 
|  |  | 
|  | if (VA.isMemLoc()) { | 
|  | // f64/i64 is passed on the stack. | 
|  | int FI = MFI.CreateFixedObject(8, VA.getLocMemOffset(), /*Immutable=*/true); | 
|  | SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); | 
|  | return DAG.getLoad(VA.getValVT(), DL, Chain, FIN, | 
|  | MachinePointerInfo::getFixedStack(MF, FI)); | 
|  | } | 
|  |  | 
|  | assert(VA.isRegLoc() && "Expected register VA assignment"); | 
|  |  | 
|  | Register LoVReg = RegInfo.createVirtualRegister(&CSKY::GPRRegClass); | 
|  | RegInfo.addLiveIn(VA.getLocReg(), LoVReg); | 
|  | SDValue Lo = DAG.getCopyFromReg(Chain, DL, LoVReg, MVT::i32); | 
|  | SDValue Hi; | 
|  | if (VA.getLocReg() == CSKY::R3) { | 
|  | // Second half of f64/i64 is passed on the stack. | 
|  | int FI = MFI.CreateFixedObject(4, 0, /*Immutable=*/true); | 
|  | SDValue FIN = DAG.getFrameIndex(FI, MVT::i32); | 
|  | Hi = DAG.getLoad(MVT::i32, DL, Chain, FIN, | 
|  | MachinePointerInfo::getFixedStack(MF, FI)); | 
|  | } else { | 
|  | // Second half of f64/i64 is passed in another GPR. | 
|  | Register HiVReg = RegInfo.createVirtualRegister(&CSKY::GPRRegClass); | 
|  | RegInfo.addLiveIn(VA.getLocReg() + 1, HiVReg); | 
|  | Hi = DAG.getCopyFromReg(Chain, DL, HiVReg, MVT::i32); | 
|  | } | 
|  | return DAG.getNode(CSKYISD::BITCAST_FROM_LOHI, DL, VA.getValVT(), Lo, Hi); | 
|  | } | 
|  |  | 
|  | // Transform physical registers into virtual registers. | 
|  | SDValue CSKYTargetLowering::LowerFormalArguments( | 
|  | SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, | 
|  | const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, | 
|  | SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { | 
|  |  | 
|  | switch (CallConv) { | 
|  | default: | 
|  | report_fatal_error("Unsupported calling convention"); | 
|  | case CallingConv::C: | 
|  | case CallingConv::Fast: | 
|  | break; | 
|  | } | 
|  |  | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  |  | 
|  | // Used with vargs to acumulate store chains. | 
|  | std::vector<SDValue> OutChains; | 
|  |  | 
|  | // Assign locations to all of the incoming arguments. | 
|  | SmallVector<CCValAssign, 16> ArgLocs; | 
|  | CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); | 
|  |  | 
|  | CCInfo.AnalyzeFormalArguments(Ins, CCAssignFnForCall(CallConv, IsVarArg)); | 
|  |  | 
|  | for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | SDValue ArgValue; | 
|  |  | 
|  | bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; | 
|  |  | 
|  | if (IsF64OnCSKY) | 
|  | ArgValue = unpack64(DAG, Chain, VA, DL); | 
|  | else if (VA.isRegLoc()) | 
|  | ArgValue = unpackFromRegLoc(Subtarget, DAG, Chain, VA, DL); | 
|  | else | 
|  | ArgValue = unpackFromMemLoc(DAG, Chain, VA, DL); | 
|  |  | 
|  | InVals.push_back(ArgValue); | 
|  | } | 
|  |  | 
|  | if (IsVarArg) { | 
|  | const unsigned XLenInBytes = 4; | 
|  | const MVT XLenVT = MVT::i32; | 
|  |  | 
|  | ArrayRef<MCPhysReg> ArgRegs = ArrayRef(GPRArgRegs); | 
|  | unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs); | 
|  | const TargetRegisterClass *RC = &CSKY::GPRRegClass; | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MachineRegisterInfo &RegInfo = MF.getRegInfo(); | 
|  | CSKYMachineFunctionInfo *CSKYFI = MF.getInfo<CSKYMachineFunctionInfo>(); | 
|  |  | 
|  | // Offset of the first variable argument from stack pointer, and size of | 
|  | // the vararg save area. For now, the varargs save area is either zero or | 
|  | // large enough to hold a0-a4. | 
|  | int VaArgOffset, VarArgsSaveSize; | 
|  |  | 
|  | // If all registers are allocated, then all varargs must be passed on the | 
|  | // stack and we don't need to save any argregs. | 
|  | if (ArgRegs.size() == Idx) { | 
|  | VaArgOffset = CCInfo.getStackSize(); | 
|  | VarArgsSaveSize = 0; | 
|  | } else { | 
|  | VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx); | 
|  | VaArgOffset = -VarArgsSaveSize; | 
|  | } | 
|  |  | 
|  | // Record the frame index of the first variable argument | 
|  | // which is a value necessary to VASTART. | 
|  | int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); | 
|  | CSKYFI->setVarArgsFrameIndex(FI); | 
|  |  | 
|  | // Copy the integer registers that may have been used for passing varargs | 
|  | // to the vararg save area. | 
|  | for (unsigned I = Idx; I < ArgRegs.size(); | 
|  | ++I, VaArgOffset += XLenInBytes) { | 
|  | const Register Reg = RegInfo.createVirtualRegister(RC); | 
|  | RegInfo.addLiveIn(ArgRegs[I], Reg); | 
|  | SDValue ArgValue = DAG.getCopyFromReg(Chain, DL, Reg, XLenVT); | 
|  | FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true); | 
|  | SDValue PtrOff = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); | 
|  | SDValue Store = DAG.getStore(Chain, DL, ArgValue, PtrOff, | 
|  | MachinePointerInfo::getFixedStack(MF, FI)); | 
|  | cast<StoreSDNode>(Store.getNode()) | 
|  | ->getMemOperand() | 
|  | ->setValue((Value *)nullptr); | 
|  | OutChains.push_back(Store); | 
|  | } | 
|  | CSKYFI->setVarArgsSaveSize(VarArgsSaveSize); | 
|  | } | 
|  |  | 
|  | // All stores are grouped in one node to allow the matching between | 
|  | // the size of Ins and InVals. This only happens for vararg functions. | 
|  | if (!OutChains.empty()) { | 
|  | OutChains.push_back(Chain); | 
|  | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains); | 
|  | } | 
|  |  | 
|  | return Chain; | 
|  | } | 
|  |  | 
|  | bool CSKYTargetLowering::CanLowerReturn( | 
|  | CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg, | 
|  | const SmallVectorImpl<ISD::OutputArg> &Outs, LLVMContext &Context, | 
|  | const Type *RetTy) const { | 
|  | SmallVector<CCValAssign, 16> CSKYLocs; | 
|  | CCState CCInfo(CallConv, IsVarArg, MF, CSKYLocs, Context); | 
|  | return CCInfo.CheckReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); | 
|  | } | 
|  |  | 
|  | SDValue | 
|  | CSKYTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, | 
|  | bool IsVarArg, | 
|  | const SmallVectorImpl<ISD::OutputArg> &Outs, | 
|  | const SmallVectorImpl<SDValue> &OutVals, | 
|  | const SDLoc &DL, SelectionDAG &DAG) const { | 
|  | // Stores the assignment of the return value to a location. | 
|  | SmallVector<CCValAssign, 16> CSKYLocs; | 
|  |  | 
|  | // Info about the registers and stack slot. | 
|  | CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), CSKYLocs, | 
|  | *DAG.getContext()); | 
|  | CCInfo.AnalyzeReturn(Outs, CCAssignFnForReturn(CallConv, IsVarArg)); | 
|  |  | 
|  | SDValue Glue; | 
|  | SmallVector<SDValue, 4> RetOps(1, Chain); | 
|  |  | 
|  | // Copy the result values into the output registers. | 
|  | for (unsigned i = 0, e = CSKYLocs.size(); i < e; ++i) { | 
|  | SDValue Val = OutVals[i]; | 
|  | CCValAssign &VA = CSKYLocs[i]; | 
|  | assert(VA.isRegLoc() && "Can only return in registers!"); | 
|  |  | 
|  | bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; | 
|  |  | 
|  | if (IsF64OnCSKY) { | 
|  |  | 
|  | assert(VA.isRegLoc() && "Expected return via registers"); | 
|  | SDValue Split64 = DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), Val); | 
|  | SDValue Lo = Split64.getValue(0); | 
|  | SDValue Hi = Split64.getValue(1); | 
|  |  | 
|  | Register RegLo = VA.getLocReg(); | 
|  | assert(RegLo < CSKY::R31 && "Invalid register pair"); | 
|  | Register RegHi = RegLo + 1; | 
|  |  | 
|  | Chain = DAG.getCopyToReg(Chain, DL, RegLo, Lo, Glue); | 
|  | Glue = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(RegLo, MVT::i32)); | 
|  | Chain = DAG.getCopyToReg(Chain, DL, RegHi, Hi, Glue); | 
|  | Glue = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(RegHi, MVT::i32)); | 
|  | } else { | 
|  | // Handle a 'normal' return. | 
|  | Val = convertValVTToLocVT(DAG, Val, VA, DL); | 
|  | Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), Val, Glue); | 
|  |  | 
|  | // Guarantee that all emitted copies are stuck together. | 
|  | Glue = Chain.getValue(1); | 
|  | RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); | 
|  | } | 
|  | } | 
|  |  | 
|  | RetOps[0] = Chain; // Update chain. | 
|  |  | 
|  | // Add the glue node if we have it. | 
|  | if (Glue.getNode()) { | 
|  | RetOps.push_back(Glue); | 
|  | } | 
|  |  | 
|  | // Interrupt service routines use different return instructions. | 
|  | if (DAG.getMachineFunction().getFunction().hasFnAttribute("interrupt")) | 
|  | return DAG.getNode(CSKYISD::NIR, DL, MVT::Other, RetOps); | 
|  |  | 
|  | return DAG.getNode(CSKYISD::RET, DL, MVT::Other, RetOps); | 
|  | } | 
|  |  | 
|  | // Lower a call to a callseq_start + CALL + callseq_end chain, and add input | 
|  | // and output parameter nodes. | 
|  | SDValue CSKYTargetLowering::LowerCall(CallLoweringInfo &CLI, | 
|  | SmallVectorImpl<SDValue> &InVals) const { | 
|  | SelectionDAG &DAG = CLI.DAG; | 
|  | SDLoc &DL = CLI.DL; | 
|  | SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs; | 
|  | SmallVectorImpl<SDValue> &OutVals = CLI.OutVals; | 
|  | SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins; | 
|  | SDValue Chain = CLI.Chain; | 
|  | SDValue Callee = CLI.Callee; | 
|  | bool &IsTailCall = CLI.IsTailCall; | 
|  | CallingConv::ID CallConv = CLI.CallConv; | 
|  | bool IsVarArg = CLI.IsVarArg; | 
|  | EVT PtrVT = getPointerTy(DAG.getDataLayout()); | 
|  | MVT XLenVT = MVT::i32; | 
|  |  | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  |  | 
|  | // Analyze the operands of the call, assigning locations to each operand. | 
|  | SmallVector<CCValAssign, 16> ArgLocs; | 
|  | CCState ArgCCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); | 
|  |  | 
|  | ArgCCInfo.AnalyzeCallOperands(Outs, CCAssignFnForCall(CallConv, IsVarArg)); | 
|  |  | 
|  | // Check if it's really possible to do a tail call. | 
|  | if (IsTailCall) | 
|  | IsTailCall = false; // TODO: TailCallOptimization; | 
|  |  | 
|  | if (IsTailCall) | 
|  | ++NumTailCalls; | 
|  | else if (CLI.CB && CLI.CB->isMustTailCall()) | 
|  | report_fatal_error("failed to perform tail call elimination on a call " | 
|  | "site marked musttail"); | 
|  |  | 
|  | // Get a count of how many bytes are to be pushed on the stack. | 
|  | unsigned NumBytes = ArgCCInfo.getStackSize(); | 
|  |  | 
|  | // Create local copies for byval args | 
|  | SmallVector<SDValue, 8> ByValArgs; | 
|  | for (unsigned i = 0, e = Outs.size(); i != e; ++i) { | 
|  | ISD::ArgFlagsTy Flags = Outs[i].Flags; | 
|  | if (!Flags.isByVal()) | 
|  | continue; | 
|  |  | 
|  | SDValue Arg = OutVals[i]; | 
|  | unsigned Size = Flags.getByValSize(); | 
|  | Align Alignment = Flags.getNonZeroByValAlign(); | 
|  |  | 
|  | int FI = | 
|  | MF.getFrameInfo().CreateStackObject(Size, Alignment, /*isSS=*/false); | 
|  | SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); | 
|  | SDValue SizeNode = DAG.getConstant(Size, DL, XLenVT); | 
|  |  | 
|  | Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Alignment, | 
|  | /*IsVolatile=*/false, | 
|  | /*AlwaysInline=*/false, /*CI=*/nullptr, IsTailCall, | 
|  | MachinePointerInfo(), MachinePointerInfo()); | 
|  | ByValArgs.push_back(FIPtr); | 
|  | } | 
|  |  | 
|  | if (!IsTailCall) | 
|  | Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, CLI.DL); | 
|  |  | 
|  | // Copy argument values to their designated locations. | 
|  | SmallVector<std::pair<Register, SDValue>, 8> RegsToPass; | 
|  | SmallVector<SDValue, 8> MemOpChains; | 
|  | SDValue StackPtr; | 
|  | for (unsigned i = 0, j = 0, e = ArgLocs.size(); i != e; ++i) { | 
|  | CCValAssign &VA = ArgLocs[i]; | 
|  | SDValue ArgValue = OutVals[i]; | 
|  | ISD::ArgFlagsTy Flags = Outs[i].Flags; | 
|  |  | 
|  | bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; | 
|  |  | 
|  | if (IsF64OnCSKY && VA.isRegLoc()) { | 
|  | SDValue Split64 = | 
|  | DAG.getNode(CSKYISD::BITCAST_TO_LOHI, DL, | 
|  | DAG.getVTList(MVT::i32, MVT::i32), ArgValue); | 
|  | SDValue Lo = Split64.getValue(0); | 
|  | SDValue Hi = Split64.getValue(1); | 
|  |  | 
|  | Register RegLo = VA.getLocReg(); | 
|  | RegsToPass.push_back(std::make_pair(RegLo, Lo)); | 
|  |  | 
|  | if (RegLo == CSKY::R3) { | 
|  | // Second half of f64/i64 is passed on the stack. | 
|  | // Work out the address of the stack slot. | 
|  | if (!StackPtr.getNode()) | 
|  | StackPtr = DAG.getCopyFromReg(Chain, DL, CSKY::R14, PtrVT); | 
|  | // Emit the store. | 
|  | MemOpChains.push_back( | 
|  | DAG.getStore(Chain, DL, Hi, StackPtr, MachinePointerInfo())); | 
|  | } else { | 
|  | // Second half of f64/i64 is passed in another GPR. | 
|  | assert(RegLo < CSKY::R31 && "Invalid register pair"); | 
|  | Register RegHigh = RegLo + 1; | 
|  | RegsToPass.push_back(std::make_pair(RegHigh, Hi)); | 
|  | } | 
|  | continue; | 
|  | } | 
|  |  | 
|  | ArgValue = convertValVTToLocVT(DAG, ArgValue, VA, DL); | 
|  |  | 
|  | // Use local copy if it is a byval arg. | 
|  | if (Flags.isByVal()) | 
|  | ArgValue = ByValArgs[j++]; | 
|  |  | 
|  | if (VA.isRegLoc()) { | 
|  | // Queue up the argument copies and emit them at the end. | 
|  | RegsToPass.push_back(std::make_pair(VA.getLocReg(), ArgValue)); | 
|  | } else { | 
|  | assert(VA.isMemLoc() && "Argument not register or memory"); | 
|  | assert(!IsTailCall && "Tail call not allowed if stack is used " | 
|  | "for passing parameters"); | 
|  |  | 
|  | // Work out the address of the stack slot. | 
|  | if (!StackPtr.getNode()) | 
|  | StackPtr = DAG.getCopyFromReg(Chain, DL, CSKY::R14, PtrVT); | 
|  | SDValue Address = | 
|  | DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, | 
|  | DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); | 
|  |  | 
|  | // Emit the store. | 
|  | MemOpChains.push_back( | 
|  | DAG.getStore(Chain, DL, ArgValue, Address, MachinePointerInfo())); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Join the stores, which are independent of one another. | 
|  | if (!MemOpChains.empty()) | 
|  | Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains); | 
|  |  | 
|  | SDValue Glue; | 
|  |  | 
|  | // Build a sequence of copy-to-reg nodes, chained and glued together. | 
|  | for (auto &Reg : RegsToPass) { | 
|  | Chain = DAG.getCopyToReg(Chain, DL, Reg.first, Reg.second, Glue); | 
|  | Glue = Chain.getValue(1); | 
|  | } | 
|  |  | 
|  | SmallVector<SDValue, 8> Ops; | 
|  | EVT Ty = getPointerTy(DAG.getDataLayout()); | 
|  | bool IsRegCall = false; | 
|  |  | 
|  | Ops.push_back(Chain); | 
|  |  | 
|  | if (GlobalAddressSDNode *S = dyn_cast<GlobalAddressSDNode>(Callee)) { | 
|  | const GlobalValue *GV = S->getGlobal(); | 
|  | bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(GV); | 
|  |  | 
|  | if (isPositionIndependent() || !Subtarget.has2E3()) { | 
|  | IsRegCall = true; | 
|  | Ops.push_back(getAddr<GlobalAddressSDNode, true>(S, DAG, IsLocal)); | 
|  | } else { | 
|  | Ops.push_back(getTargetNode(cast<GlobalAddressSDNode>(Callee), DL, Ty, | 
|  | DAG, CSKYII::MO_None)); | 
|  | Ops.push_back(getTargetConstantPoolValue( | 
|  | cast<GlobalAddressSDNode>(Callee), Ty, DAG, CSKYII::MO_None)); | 
|  | } | 
|  | } else if (ExternalSymbolSDNode *S = dyn_cast<ExternalSymbolSDNode>(Callee)) { | 
|  | bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(nullptr); | 
|  |  | 
|  | if (isPositionIndependent() || !Subtarget.has2E3()) { | 
|  | IsRegCall = true; | 
|  | Ops.push_back(getAddr<ExternalSymbolSDNode, true>(S, DAG, IsLocal)); | 
|  | } else { | 
|  | Ops.push_back(getTargetNode(cast<ExternalSymbolSDNode>(Callee), DL, Ty, | 
|  | DAG, CSKYII::MO_None)); | 
|  | Ops.push_back(getTargetConstantPoolValue( | 
|  | cast<ExternalSymbolSDNode>(Callee), Ty, DAG, CSKYII::MO_None)); | 
|  | } | 
|  | } else { | 
|  | IsRegCall = true; | 
|  | Ops.push_back(Callee); | 
|  | } | 
|  |  | 
|  | // Add argument registers to the end of the list so that they are | 
|  | // known live into the call. | 
|  | for (auto &Reg : RegsToPass) | 
|  | Ops.push_back(DAG.getRegister(Reg.first, Reg.second.getValueType())); | 
|  |  | 
|  | if (!IsTailCall) { | 
|  | // Add a register mask operand representing the call-preserved registers. | 
|  | const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo(); | 
|  | const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); | 
|  | assert(Mask && "Missing call preserved mask for calling convention"); | 
|  | Ops.push_back(DAG.getRegisterMask(Mask)); | 
|  | } | 
|  |  | 
|  | // Glue the call to the argument copies, if any. | 
|  | if (Glue.getNode()) | 
|  | Ops.push_back(Glue); | 
|  |  | 
|  | // Emit the call. | 
|  | SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); | 
|  |  | 
|  | if (IsTailCall) { | 
|  | MF.getFrameInfo().setHasTailCall(); | 
|  | return DAG.getNode(IsRegCall ? CSKYISD::TAILReg : CSKYISD::TAIL, DL, | 
|  | NodeTys, Ops); | 
|  | } | 
|  |  | 
|  | Chain = DAG.getNode(IsRegCall ? CSKYISD::CALLReg : CSKYISD::CALL, DL, NodeTys, | 
|  | Ops); | 
|  | DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); | 
|  | Glue = Chain.getValue(1); | 
|  |  | 
|  | // Mark the end of the call, which is glued to the call itself. | 
|  | Chain = DAG.getCALLSEQ_END(Chain, NumBytes, 0, Glue, DL); | 
|  | Glue = Chain.getValue(1); | 
|  |  | 
|  | // Assign locations to each value returned by this call. | 
|  | SmallVector<CCValAssign, 16> CSKYLocs; | 
|  | CCState RetCCInfo(CallConv, IsVarArg, MF, CSKYLocs, *DAG.getContext()); | 
|  | RetCCInfo.AnalyzeCallResult(Ins, CCAssignFnForReturn(CallConv, IsVarArg)); | 
|  |  | 
|  | // Copy all of the result registers out of their specified physreg. | 
|  | for (auto &VA : CSKYLocs) { | 
|  | // Copy the value out | 
|  | SDValue RetValue = | 
|  | DAG.getCopyFromReg(Chain, DL, VA.getLocReg(), VA.getLocVT(), Glue); | 
|  | // Glue the RetValue to the end of the call sequence | 
|  | Chain = RetValue.getValue(1); | 
|  | Glue = RetValue.getValue(2); | 
|  |  | 
|  | bool IsF64OnCSKY = VA.getLocVT() == MVT::i32 && VA.getValVT() == MVT::f64; | 
|  |  | 
|  | if (IsF64OnCSKY) { | 
|  | assert(VA.getLocReg() == GPRArgRegs[0] && "Unexpected reg assignment"); | 
|  | SDValue RetValue2 = | 
|  | DAG.getCopyFromReg(Chain, DL, GPRArgRegs[1], MVT::i32, Glue); | 
|  | Chain = RetValue2.getValue(1); | 
|  | Glue = RetValue2.getValue(2); | 
|  | RetValue = DAG.getNode(CSKYISD::BITCAST_FROM_LOHI, DL, VA.getValVT(), | 
|  | RetValue, RetValue2); | 
|  | } | 
|  |  | 
|  | RetValue = convertLocVTToValVT(DAG, RetValue, VA, DL); | 
|  |  | 
|  | InVals.push_back(RetValue); | 
|  | } | 
|  |  | 
|  | return Chain; | 
|  | } | 
|  |  | 
|  | CCAssignFn *CSKYTargetLowering::CCAssignFnForReturn(CallingConv::ID CC, | 
|  | bool IsVarArg) const { | 
|  | if (IsVarArg || !Subtarget.useHardFloatABI()) | 
|  | return RetCC_CSKY_ABIV2_SOFT; | 
|  | else | 
|  | return RetCC_CSKY_ABIV2_FP; | 
|  | } | 
|  |  | 
|  | CCAssignFn *CSKYTargetLowering::CCAssignFnForCall(CallingConv::ID CC, | 
|  | bool IsVarArg) const { | 
|  | if (IsVarArg || !Subtarget.useHardFloatABI()) | 
|  | return CC_CSKY_ABIV2_SOFT; | 
|  | else | 
|  | return CC_CSKY_ABIV2_FP; | 
|  | } | 
|  |  | 
|  | static CSKYCP::CSKYCPModifier getModifier(unsigned Flags) { | 
|  |  | 
|  | if (Flags == CSKYII::MO_ADDR32) | 
|  | return CSKYCP::ADDR; | 
|  | else if (Flags == CSKYII::MO_GOT32) | 
|  | return CSKYCP::GOT; | 
|  | else if (Flags == CSKYII::MO_GOTOFF) | 
|  | return CSKYCP::GOTOFF; | 
|  | else if (Flags == CSKYII::MO_PLT32) | 
|  | return CSKYCP::PLT; | 
|  | else if (Flags == CSKYII::MO_None) | 
|  | return CSKYCP::NO_MOD; | 
|  | else | 
|  | assert(0 && "unknown CSKYII Modifier"); | 
|  | return CSKYCP::NO_MOD; | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetConstantPoolValue(GlobalAddressSDNode *N, | 
|  | EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | CSKYConstantPoolValue *CPV = CSKYConstantPoolConstant::Create( | 
|  | N->getGlobal(), CSKYCP::CPValue, 0, getModifier(Flags), false); | 
|  |  | 
|  | return DAG.getTargetConstantPool(CPV, Ty); | 
|  | } | 
|  |  | 
|  | CSKYTargetLowering::ConstraintType | 
|  | CSKYTargetLowering::getConstraintType(StringRef Constraint) const { | 
|  | if (Constraint.size() == 1) { | 
|  | switch (Constraint[0]) { | 
|  | default: | 
|  | break; | 
|  | case 'a': | 
|  | case 'b': | 
|  | case 'v': | 
|  | case 'w': | 
|  | case 'y': | 
|  | return C_RegisterClass; | 
|  | case 'c': | 
|  | case 'l': | 
|  | case 'h': | 
|  | case 'z': | 
|  | return C_Register; | 
|  | } | 
|  | } | 
|  | return TargetLowering::getConstraintType(Constraint); | 
|  | } | 
|  |  | 
|  | std::pair<unsigned, const TargetRegisterClass *> | 
|  | CSKYTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, | 
|  | StringRef Constraint, | 
|  | MVT VT) const { | 
|  | if (Constraint.size() == 1) { | 
|  | switch (Constraint[0]) { | 
|  | case 'r': | 
|  | return std::make_pair(0U, &CSKY::GPRRegClass); | 
|  | case 'a': | 
|  | return std::make_pair(0U, &CSKY::mGPRRegClass); | 
|  | case 'b': | 
|  | return std::make_pair(0U, &CSKY::sGPRRegClass); | 
|  | case 'z': | 
|  | return std::make_pair(CSKY::R14, &CSKY::GPRRegClass); | 
|  | case 'c': | 
|  | return std::make_pair(CSKY::C, &CSKY::CARRYRegClass); | 
|  | case 'w': | 
|  | if ((Subtarget.hasFPUv2SingleFloat() || | 
|  | Subtarget.hasFPUv3SingleFloat()) && | 
|  | VT == MVT::f32) | 
|  | return std::make_pair(0U, &CSKY::sFPR32RegClass); | 
|  | if ((Subtarget.hasFPUv2DoubleFloat() || | 
|  | Subtarget.hasFPUv3DoubleFloat()) && | 
|  | VT == MVT::f64) | 
|  | return std::make_pair(0U, &CSKY::sFPR64RegClass); | 
|  | break; | 
|  | case 'v': | 
|  | if (Subtarget.hasFPUv2SingleFloat() && VT == MVT::f32) | 
|  | return std::make_pair(0U, &CSKY::sFPR32RegClass); | 
|  | if (Subtarget.hasFPUv3SingleFloat() && VT == MVT::f32) | 
|  | return std::make_pair(0U, &CSKY::FPR32RegClass); | 
|  | if (Subtarget.hasFPUv2DoubleFloat() && VT == MVT::f64) | 
|  | return std::make_pair(0U, &CSKY::sFPR64RegClass); | 
|  | if (Subtarget.hasFPUv3DoubleFloat() && VT == MVT::f64) | 
|  | return std::make_pair(0U, &CSKY::FPR64RegClass); | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Constraint == "{c}") | 
|  | return std::make_pair(CSKY::C, &CSKY::CARRYRegClass); | 
|  |  | 
|  | // Clang will correctly decode the usage of register name aliases into their | 
|  | // official names. However, other frontends like `rustc` do not. This allows | 
|  | // users of these frontends to use the ABI names for registers in LLVM-style | 
|  | // register constraints. | 
|  | unsigned XRegFromAlias = StringSwitch<unsigned>(Constraint.lower()) | 
|  | .Case("{a0}", CSKY::R0) | 
|  | .Case("{a1}", CSKY::R1) | 
|  | .Case("{a2}", CSKY::R2) | 
|  | .Case("{a3}", CSKY::R3) | 
|  | .Case("{l0}", CSKY::R4) | 
|  | .Case("{l1}", CSKY::R5) | 
|  | .Case("{l2}", CSKY::R6) | 
|  | .Case("{l3}", CSKY::R7) | 
|  | .Case("{l4}", CSKY::R8) | 
|  | .Case("{l5}", CSKY::R9) | 
|  | .Case("{l6}", CSKY::R10) | 
|  | .Case("{l7}", CSKY::R11) | 
|  | .Case("{t0}", CSKY::R12) | 
|  | .Case("{t1}", CSKY::R13) | 
|  | .Case("{sp}", CSKY::R14) | 
|  | .Case("{lr}", CSKY::R15) | 
|  | .Case("{l8}", CSKY::R16) | 
|  | .Case("{l9}", CSKY::R17) | 
|  | .Case("{t2}", CSKY::R18) | 
|  | .Case("{t3}", CSKY::R19) | 
|  | .Case("{t4}", CSKY::R20) | 
|  | .Case("{t5}", CSKY::R21) | 
|  | .Case("{t6}", CSKY::R22) | 
|  | .Cases("{t7}", "{fp}", CSKY::R23) | 
|  | .Cases("{t8}", "{top}", CSKY::R24) | 
|  | .Cases("{t9}", "{bsp}", CSKY::R25) | 
|  | .Case("{r26}", CSKY::R26) | 
|  | .Case("{r27}", CSKY::R27) | 
|  | .Cases("{gb}", "{rgb}", "{rdb}", CSKY::R28) | 
|  | .Cases("{tb}", "{rtb}", CSKY::R29) | 
|  | .Case("{svbr}", CSKY::R30) | 
|  | .Case("{tls}", CSKY::R31) | 
|  | .Default(CSKY::NoRegister); | 
|  |  | 
|  | if (XRegFromAlias != CSKY::NoRegister) | 
|  | return std::make_pair(XRegFromAlias, &CSKY::GPRRegClass); | 
|  |  | 
|  | // Since TargetLowering::getRegForInlineAsmConstraint uses the name of the | 
|  | // TableGen record rather than the AsmName to choose registers for InlineAsm | 
|  | // constraints, plus we want to match those names to the widest floating point | 
|  | // register type available, manually select floating point registers here. | 
|  | // | 
|  | // The second case is the ABI name of the register, so that frontends can also | 
|  | // use the ABI names in register constraint lists. | 
|  | if (Subtarget.useHardFloat()) { | 
|  | unsigned FReg = StringSwitch<unsigned>(Constraint.lower()) | 
|  | .Cases("{fr0}", "{vr0}", CSKY::F0_32) | 
|  | .Cases("{fr1}", "{vr1}", CSKY::F1_32) | 
|  | .Cases("{fr2}", "{vr2}", CSKY::F2_32) | 
|  | .Cases("{fr3}", "{vr3}", CSKY::F3_32) | 
|  | .Cases("{fr4}", "{vr4}", CSKY::F4_32) | 
|  | .Cases("{fr5}", "{vr5}", CSKY::F5_32) | 
|  | .Cases("{fr6}", "{vr6}", CSKY::F6_32) | 
|  | .Cases("{fr7}", "{vr7}", CSKY::F7_32) | 
|  | .Cases("{fr8}", "{vr8}", CSKY::F8_32) | 
|  | .Cases("{fr9}", "{vr9}", CSKY::F9_32) | 
|  | .Cases("{fr10}", "{vr10}", CSKY::F10_32) | 
|  | .Cases("{fr11}", "{vr11}", CSKY::F11_32) | 
|  | .Cases("{fr12}", "{vr12}", CSKY::F12_32) | 
|  | .Cases("{fr13}", "{vr13}", CSKY::F13_32) | 
|  | .Cases("{fr14}", "{vr14}", CSKY::F14_32) | 
|  | .Cases("{fr15}", "{vr15}", CSKY::F15_32) | 
|  | .Cases("{fr16}", "{vr16}", CSKY::F16_32) | 
|  | .Cases("{fr17}", "{vr17}", CSKY::F17_32) | 
|  | .Cases("{fr18}", "{vr18}", CSKY::F18_32) | 
|  | .Cases("{fr19}", "{vr19}", CSKY::F19_32) | 
|  | .Cases("{fr20}", "{vr20}", CSKY::F20_32) | 
|  | .Cases("{fr21}", "{vr21}", CSKY::F21_32) | 
|  | .Cases("{fr22}", "{vr22}", CSKY::F22_32) | 
|  | .Cases("{fr23}", "{vr23}", CSKY::F23_32) | 
|  | .Cases("{fr24}", "{vr24}", CSKY::F24_32) | 
|  | .Cases("{fr25}", "{vr25}", CSKY::F25_32) | 
|  | .Cases("{fr26}", "{vr26}", CSKY::F26_32) | 
|  | .Cases("{fr27}", "{vr27}", CSKY::F27_32) | 
|  | .Cases("{fr28}", "{vr28}", CSKY::F28_32) | 
|  | .Cases("{fr29}", "{vr29}", CSKY::F29_32) | 
|  | .Cases("{fr30}", "{vr30}", CSKY::F30_32) | 
|  | .Cases("{fr31}", "{vr31}", CSKY::F31_32) | 
|  | .Default(CSKY::NoRegister); | 
|  | if (FReg != CSKY::NoRegister) { | 
|  | assert(CSKY::F0_32 <= FReg && FReg <= CSKY::F31_32 && "Unknown fp-reg"); | 
|  | unsigned RegNo = FReg - CSKY::F0_32; | 
|  | unsigned DReg = CSKY::F0_64 + RegNo; | 
|  |  | 
|  | if (Subtarget.hasFPUv2DoubleFloat()) | 
|  | return std::make_pair(DReg, &CSKY::sFPR64RegClass); | 
|  | else if (Subtarget.hasFPUv3DoubleFloat()) | 
|  | return std::make_pair(DReg, &CSKY::FPR64RegClass); | 
|  | else if (Subtarget.hasFPUv2SingleFloat()) | 
|  | return std::make_pair(FReg, &CSKY::sFPR32RegClass); | 
|  | else if (Subtarget.hasFPUv3SingleFloat()) | 
|  | return std::make_pair(FReg, &CSKY::FPR32RegClass); | 
|  | } | 
|  | } | 
|  |  | 
|  | return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); | 
|  | } | 
|  |  | 
|  | static MachineBasicBlock * | 
|  | emitSelectPseudo(MachineInstr &MI, MachineBasicBlock *BB, unsigned Opcode) { | 
|  |  | 
|  | const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo(); | 
|  | DebugLoc DL = MI.getDebugLoc(); | 
|  |  | 
|  | // To "insert" a SELECT instruction, we actually have to insert the | 
|  | // diamond control-flow pattern.  The incoming instruction knows the | 
|  | // destination vreg to set, the condition code register to branch on, the | 
|  | // true/false values to select between, and a branch opcode to use. | 
|  | const BasicBlock *LLVM_BB = BB->getBasicBlock(); | 
|  | MachineFunction::iterator It = ++BB->getIterator(); | 
|  |  | 
|  | //  thisMBB: | 
|  | //  ... | 
|  | //   TrueVal = ... | 
|  | //   bt32 c, sinkMBB | 
|  | //   fallthrough --> copyMBB | 
|  | MachineBasicBlock *thisMBB = BB; | 
|  | MachineFunction *F = BB->getParent(); | 
|  | MachineBasicBlock *copyMBB = F->CreateMachineBasicBlock(LLVM_BB); | 
|  | MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB); | 
|  | F->insert(It, copyMBB); | 
|  | F->insert(It, sinkMBB); | 
|  |  | 
|  | // Transfer the remainder of BB and its successor edges to sinkMBB. | 
|  | sinkMBB->splice(sinkMBB->begin(), BB, | 
|  | std::next(MachineBasicBlock::iterator(MI)), BB->end()); | 
|  | sinkMBB->transferSuccessorsAndUpdatePHIs(BB); | 
|  |  | 
|  | // Next, add the true and fallthrough blocks as its successors. | 
|  | BB->addSuccessor(copyMBB); | 
|  | BB->addSuccessor(sinkMBB); | 
|  |  | 
|  | // bt32 condition, sinkMBB | 
|  | BuildMI(BB, DL, TII.get(Opcode)) | 
|  | .addReg(MI.getOperand(1).getReg()) | 
|  | .addMBB(sinkMBB); | 
|  |  | 
|  | //  copyMBB: | 
|  | //   %FalseValue = ... | 
|  | //   # fallthrough to sinkMBB | 
|  | BB = copyMBB; | 
|  |  | 
|  | // Update machine-CFG edges | 
|  | BB->addSuccessor(sinkMBB); | 
|  |  | 
|  | //  sinkMBB: | 
|  | //   %Result = phi [ %TrueValue, thisMBB ], [ %FalseValue, copyMBB ] | 
|  | //  ... | 
|  | BB = sinkMBB; | 
|  |  | 
|  | BuildMI(*BB, BB->begin(), DL, TII.get(CSKY::PHI), MI.getOperand(0).getReg()) | 
|  | .addReg(MI.getOperand(2).getReg()) | 
|  | .addMBB(thisMBB) | 
|  | .addReg(MI.getOperand(3).getReg()) | 
|  | .addMBB(copyMBB); | 
|  |  | 
|  | MI.eraseFromParent(); // The pseudo instruction is gone now. | 
|  |  | 
|  | return BB; | 
|  | } | 
|  |  | 
|  | MachineBasicBlock * | 
|  | CSKYTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, | 
|  | MachineBasicBlock *BB) const { | 
|  | switch (MI.getOpcode()) { | 
|  | default: | 
|  | llvm_unreachable("Unexpected instr type to insert"); | 
|  | case CSKY::FSELS: | 
|  | case CSKY::FSELD: | 
|  | if (Subtarget.hasE2()) | 
|  | return emitSelectPseudo(MI, BB, CSKY::BT32); | 
|  | else | 
|  | return emitSelectPseudo(MI, BB, CSKY::BT16); | 
|  | case CSKY::ISEL32: | 
|  | return emitSelectPseudo(MI, BB, CSKY::BT32); | 
|  | case CSKY::ISEL16: | 
|  | return emitSelectPseudo(MI, BB, CSKY::BT16); | 
|  | } | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetConstantPoolValue(ExternalSymbolSDNode *N, | 
|  | EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | CSKYConstantPoolValue *CPV = | 
|  | CSKYConstantPoolSymbol::Create(Type::getInt32Ty(*DAG.getContext()), | 
|  | N->getSymbol(), 0, getModifier(Flags)); | 
|  |  | 
|  | return DAG.getTargetConstantPool(CPV, Ty); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetConstantPoolValue(JumpTableSDNode *N, | 
|  | EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | CSKYConstantPoolValue *CPV = | 
|  | CSKYConstantPoolJT::Create(Type::getInt32Ty(*DAG.getContext()), | 
|  | N->getIndex(), 0, getModifier(Flags)); | 
|  | return DAG.getTargetConstantPool(CPV, Ty); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetConstantPoolValue(BlockAddressSDNode *N, | 
|  | EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | assert(N->getOffset() == 0); | 
|  | CSKYConstantPoolValue *CPV = CSKYConstantPoolConstant::Create( | 
|  | N->getBlockAddress(), CSKYCP::CPBlockAddress, 0, getModifier(Flags), | 
|  | false); | 
|  | return DAG.getTargetConstantPool(CPV, Ty); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetConstantPoolValue(ConstantPoolSDNode *N, | 
|  | EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | assert(N->getOffset() == 0); | 
|  | CSKYConstantPoolValue *CPV = CSKYConstantPoolConstant::Create( | 
|  | N->getConstVal(), Type::getInt32Ty(*DAG.getContext()), | 
|  | CSKYCP::CPConstPool, 0, getModifier(Flags), false); | 
|  | return DAG.getTargetConstantPool(CPV, Ty); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetNode(GlobalAddressSDNode *N, SDLoc DL, | 
|  | EVT Ty, SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetNode(ExternalSymbolSDNode *N, SDLoc DL, | 
|  | EVT Ty, SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | return DAG.getTargetExternalSymbol(N->getSymbol(), Ty, Flags); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetNode(JumpTableSDNode *N, SDLoc DL, EVT Ty, | 
|  | SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | return DAG.getTargetJumpTable(N->getIndex(), Ty, Flags); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetNode(BlockAddressSDNode *N, SDLoc DL, | 
|  | EVT Ty, SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  | return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(), | 
|  | Flags); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getTargetNode(ConstantPoolSDNode *N, SDLoc DL, | 
|  | EVT Ty, SelectionDAG &DAG, | 
|  | unsigned Flags) const { | 
|  |  | 
|  | return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlign(), | 
|  | N->getOffset(), Flags); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerGlobalAddress(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | SDLoc DL(Op); | 
|  | EVT Ty = Op.getValueType(); | 
|  | GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); | 
|  | int64_t Offset = N->getOffset(); | 
|  |  | 
|  | const GlobalValue *GV = N->getGlobal(); | 
|  | bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(GV); | 
|  | SDValue Addr = getAddr<GlobalAddressSDNode, false>(N, DAG, IsLocal); | 
|  |  | 
|  | // In order to maximise the opportunity for common subexpression elimination, | 
|  | // emit a separate ADD node for the global address offset instead of folding | 
|  | // it in the global address node. Later peephole optimisations may choose to | 
|  | // fold it back in when profitable. | 
|  | if (Offset != 0) | 
|  | return DAG.getNode(ISD::ADD, DL, Ty, Addr, | 
|  | DAG.getConstant(Offset, DL, MVT::i32)); | 
|  | return Addr; | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerExternalSymbol(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | ExternalSymbolSDNode *N = cast<ExternalSymbolSDNode>(Op); | 
|  |  | 
|  | return getAddr(N, DAG, false); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerJumpTable(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | JumpTableSDNode *N = cast<JumpTableSDNode>(Op); | 
|  |  | 
|  | return getAddr<JumpTableSDNode, false>(N, DAG); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerBlockAddress(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op); | 
|  |  | 
|  | return getAddr(N, DAG); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerConstantPool(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | assert(!Subtarget.hasE2()); | 
|  | ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); | 
|  |  | 
|  | return getAddr(N, DAG); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | CSKYMachineFunctionInfo *FuncInfo = MF.getInfo<CSKYMachineFunctionInfo>(); | 
|  |  | 
|  | SDLoc DL(Op); | 
|  | SDValue FI = DAG.getFrameIndex(FuncInfo->getVarArgsFrameIndex(), | 
|  | getPointerTy(MF.getDataLayout())); | 
|  |  | 
|  | // vastart just stores the address of the VarArgsFrameIndex slot into the | 
|  | // memory location argument. | 
|  | const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); | 
|  | return DAG.getStore(Op.getOperand(0), DL, FI, Op.getOperand(1), | 
|  | MachinePointerInfo(SV)); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerFRAMEADDR(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | const CSKYRegisterInfo &RI = *Subtarget.getRegisterInfo(); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MFI.setFrameAddressIsTaken(true); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  | unsigned Depth = Op.getConstantOperandVal(0); | 
|  | Register FrameReg = RI.getFrameRegister(MF); | 
|  | SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT); | 
|  | while (Depth--) | 
|  | FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr, | 
|  | MachinePointerInfo()); | 
|  | return FrameAddr; | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerRETURNADDR(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | const CSKYRegisterInfo &RI = *Subtarget.getRegisterInfo(); | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | MachineFrameInfo &MFI = MF.getFrameInfo(); | 
|  | MFI.setReturnAddressIsTaken(true); | 
|  |  | 
|  | EVT VT = Op.getValueType(); | 
|  | SDLoc dl(Op); | 
|  | unsigned Depth = Op.getConstantOperandVal(0); | 
|  | if (Depth) { | 
|  | SDValue FrameAddr = LowerFRAMEADDR(Op, DAG); | 
|  | SDValue Offset = DAG.getConstant(4, dl, MVT::i32); | 
|  | return DAG.getLoad(VT, dl, DAG.getEntryNode(), | 
|  | DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset), | 
|  | MachinePointerInfo()); | 
|  | } | 
|  | // Return the value of the return address register, marking it an implicit | 
|  | // live-in. | 
|  | unsigned Reg = MF.addLiveIn(RI.getRARegister(), getRegClassFor(MVT::i32)); | 
|  | return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT); | 
|  | } | 
|  |  | 
|  | Register CSKYTargetLowering::getExceptionPointerRegister( | 
|  | const Constant *PersonalityFn) const { | 
|  | return CSKY::R0; | 
|  | } | 
|  |  | 
|  | Register CSKYTargetLowering::getExceptionSelectorRegister( | 
|  | const Constant *PersonalityFn) const { | 
|  | return CSKY::R1; | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::LowerGlobalTLSAddress(SDValue Op, | 
|  | SelectionDAG &DAG) const { | 
|  | SDLoc DL(Op); | 
|  | EVT Ty = Op.getValueType(); | 
|  | GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op); | 
|  | int64_t Offset = N->getOffset(); | 
|  | MVT XLenVT = MVT::i32; | 
|  |  | 
|  | TLSModel::Model Model = getTargetMachine().getTLSModel(N->getGlobal()); | 
|  | SDValue Addr; | 
|  | switch (Model) { | 
|  | case TLSModel::LocalExec: | 
|  | Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/false); | 
|  | break; | 
|  | case TLSModel::InitialExec: | 
|  | Addr = getStaticTLSAddr(N, DAG, /*UseGOT=*/true); | 
|  | break; | 
|  | case TLSModel::LocalDynamic: | 
|  | case TLSModel::GeneralDynamic: | 
|  | Addr = getDynamicTLSAddr(N, DAG); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // In order to maximise the opportunity for common subexpression elimination, | 
|  | // emit a separate ADD node for the global address offset instead of folding | 
|  | // it in the global address node. Later peephole optimisations may choose to | 
|  | // fold it back in when profitable. | 
|  | if (Offset != 0) | 
|  | return DAG.getNode(ISD::ADD, DL, Ty, Addr, | 
|  | DAG.getConstant(Offset, DL, XLenVT)); | 
|  | return Addr; | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getStaticTLSAddr(GlobalAddressSDNode *N, | 
|  | SelectionDAG &DAG, | 
|  | bool UseGOT) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); | 
|  |  | 
|  | unsigned CSKYPCLabelIndex = CFI->createPICLabelUId(); | 
|  |  | 
|  | SDLoc DL(N); | 
|  | EVT Ty = getPointerTy(DAG.getDataLayout()); | 
|  |  | 
|  | CSKYCP::CSKYCPModifier Flag = UseGOT ? CSKYCP::TLSIE : CSKYCP::TLSLE; | 
|  | bool AddCurrentAddr = UseGOT ? true : false; | 
|  | unsigned char PCAjust = UseGOT ? 4 : 0; | 
|  |  | 
|  | CSKYConstantPoolValue *CPV = | 
|  | CSKYConstantPoolConstant::Create(N->getGlobal(), CSKYCP::CPValue, PCAjust, | 
|  | Flag, AddCurrentAddr, CSKYPCLabelIndex); | 
|  | SDValue CAddr = DAG.getTargetConstantPool(CPV, Ty); | 
|  |  | 
|  | SDValue Load; | 
|  | if (UseGOT) { | 
|  | SDValue PICLabel = DAG.getTargetConstant(CSKYPCLabelIndex, DL, MVT::i32); | 
|  | auto *LRWGRS = DAG.getMachineNode(CSKY::PseudoTLSLA32, DL, {Ty, Ty}, | 
|  | {CAddr, PICLabel}); | 
|  | auto LRWADDGRS = | 
|  | DAG.getNode(ISD::ADD, DL, Ty, SDValue(LRWGRS, 0), SDValue(LRWGRS, 1)); | 
|  | Load = DAG.getLoad(Ty, DL, DAG.getEntryNode(), LRWADDGRS, | 
|  | MachinePointerInfo(N->getGlobal())); | 
|  | } else { | 
|  | Load = SDValue(DAG.getMachineNode(CSKY::LRW32, DL, Ty, CAddr), 0); | 
|  | } | 
|  |  | 
|  | // Add the thread pointer. | 
|  | SDValue TPReg = DAG.getRegister(CSKY::R31, MVT::i32); | 
|  | return DAG.getNode(ISD::ADD, DL, Ty, Load, TPReg); | 
|  | } | 
|  |  | 
|  | SDValue CSKYTargetLowering::getDynamicTLSAddr(GlobalAddressSDNode *N, | 
|  | SelectionDAG &DAG) const { | 
|  | MachineFunction &MF = DAG.getMachineFunction(); | 
|  | CSKYMachineFunctionInfo *CFI = MF.getInfo<CSKYMachineFunctionInfo>(); | 
|  |  | 
|  | unsigned CSKYPCLabelIndex = CFI->createPICLabelUId(); | 
|  |  | 
|  | SDLoc DL(N); | 
|  | EVT Ty = getPointerTy(DAG.getDataLayout()); | 
|  | IntegerType *CallTy = Type::getIntNTy(*DAG.getContext(), Ty.getSizeInBits()); | 
|  |  | 
|  | CSKYConstantPoolValue *CPV = | 
|  | CSKYConstantPoolConstant::Create(N->getGlobal(), CSKYCP::CPValue, 4, | 
|  | CSKYCP::TLSGD, true, CSKYPCLabelIndex); | 
|  | SDValue Addr = DAG.getTargetConstantPool(CPV, Ty); | 
|  | SDValue PICLabel = DAG.getTargetConstant(CSKYPCLabelIndex, DL, MVT::i32); | 
|  |  | 
|  | auto *LRWGRS = | 
|  | DAG.getMachineNode(CSKY::PseudoTLSLA32, DL, {Ty, Ty}, {Addr, PICLabel}); | 
|  |  | 
|  | auto Load = | 
|  | DAG.getNode(ISD::ADD, DL, Ty, SDValue(LRWGRS, 0), SDValue(LRWGRS, 1)); | 
|  |  | 
|  | // Prepare argument list to generate call. | 
|  | ArgListTy Args; | 
|  | Args.emplace_back(Load, CallTy); | 
|  |  | 
|  | // Setup call to __tls_get_addr. | 
|  | TargetLowering::CallLoweringInfo CLI(DAG); | 
|  | CLI.setDebugLoc(DL) | 
|  | .setChain(DAG.getEntryNode()) | 
|  | .setLibCallee(CallingConv::C, CallTy, | 
|  | DAG.getExternalSymbol("__tls_get_addr", Ty), | 
|  | std::move(Args)); | 
|  | SDValue V = LowerCallTo(CLI).first; | 
|  |  | 
|  | return V; | 
|  | } | 
|  |  | 
|  | bool CSKYTargetLowering::decomposeMulByConstant(LLVMContext &Context, EVT VT, | 
|  | SDValue C) const { | 
|  | if (!VT.isScalarInteger()) | 
|  | return false; | 
|  |  | 
|  | // Omit if data size exceeds. | 
|  | if (VT.getSizeInBits() > Subtarget.XLen) | 
|  | return false; | 
|  |  | 
|  | if (auto *ConstNode = dyn_cast<ConstantSDNode>(C.getNode())) { | 
|  | const APInt &Imm = ConstNode->getAPIntValue(); | 
|  | // Break MULT to LSLI + ADDU/SUBU. | 
|  | if ((Imm + 1).isPowerOf2() || (Imm - 1).isPowerOf2() || | 
|  | (1 - Imm).isPowerOf2()) | 
|  | return true; | 
|  | // Only break MULT for sub targets without MULT32, since an extra | 
|  | // instruction will be generated against the above 3 cases. We leave it | 
|  | // unchanged on sub targets with MULT32, since not sure it is better. | 
|  | if (!Subtarget.hasE2() && (-1 - Imm).isPowerOf2()) | 
|  | return true; | 
|  | // Break (MULT x, imm) to ([IXH32|IXW32|IXD32] (LSLI32 x, i0), x) when | 
|  | // imm=(1<<i0)+[2|4|8] and imm has to be composed via a MOVIH32/ORI32 pair. | 
|  | if (Imm.ugt(0xffff) && ((Imm - 2).isPowerOf2() || (Imm - 4).isPowerOf2()) && | 
|  | Subtarget.hasE2()) | 
|  | return true; | 
|  | if (Imm.ugt(0xffff) && (Imm - 8).isPowerOf2() && Subtarget.has2E3()) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool CSKYTargetLowering::isCheapToSpeculateCttz(Type *Ty) const { | 
|  | return Subtarget.has2E3(); | 
|  | } | 
|  |  | 
|  | bool CSKYTargetLowering::isCheapToSpeculateCtlz(Type *Ty) const { | 
|  | return Subtarget.hasE2(); | 
|  | } |