/*! \param Op The ISD instruction operand \param N The address to be tested \param Base The base address \param Index The base address index */ bool SPUDAGToDAGISel::SelectAFormAddr(SDNode *Op, SDValue N, SDValue &Base, SDValue &Index) { // These match the addr256k operand type: EVT OffsVT = MVT::i16; SDValue Zero = CurDAG->getTargetConstant(0, OffsVT); int64_t val; switch (N.getOpcode()) { case ISD::Constant: val = dyn_cast<ConstantSDNode>(N.getNode())->getSExtValue(); Base = CurDAG->getTargetConstant( val , MVT::i32); Index = Zero; return true; case ISD::ConstantPool: case ISD::GlobalAddress: report_fatal_error("SPU SelectAFormAddr: Pool/Global not lowered."); /*NOTREACHED*/ case ISD::TargetConstant: case ISD::TargetGlobalAddress: case ISD::TargetJumpTable: report_fatal_error("SPUSelectAFormAddr: Target Constant/Pool/Global " "not wrapped as A-form address."); /*NOTREACHED*/ case SPUISD::AFormAddr: // Just load from memory if there's only a single use of the location, // otherwise, this will get handled below with D-form offset addresses if (N.hasOneUse()) { SDValue Op0 = N.getOperand(0); switch (Op0.getOpcode()) { case ISD::TargetConstantPool: case ISD::TargetJumpTable: Base = Op0; Index = Zero; return true; case ISD::TargetGlobalAddress: { GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op0); const GlobalValue *GV = GSDN->getGlobal(); if (GV->getAlignment() == 16) { Base = Op0; Index = Zero; return true; } break; } } } break; } return false; }
SDNode *VDAGToDAGISel::SelectImmediate(SDNode *N, bool ForceMove) { SDValue Imm = SDValue(N, 0); DebugLoc dl = Imm.getDebugLoc(); if (ConstantSDNode *CSD = dyn_cast<ConstantSDNode>(N)) { // Do not need to select target constant. if (CSD->getOpcode() == ISD::TargetConstant && !ForceMove) return 0; // FIXME: We do not need this since we have the bit width operand to hold // the bit width of a constant. // Build the target constant. int64_t Val = CSD->getZExtValue(); Imm = CurDAG->getTargetConstant(Val, N->getValueType(0)); } else if (ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(N)) Imm = CurDAG->getTargetExternalSymbol(ES->getSymbol(), Imm.getValueType(), Imm.getValueSizeInBits()); else { GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(N); Imm = CurDAG->getTargetGlobalAddress(GA->getGlobal(), dl, Imm.getValueType(), GA->getOffset(), Imm.getValueSizeInBits()); } SDValue Ops[] = { Imm, SDValue()/*The dummy bit width operand*/, CurDAG->getTargetConstant(0, MVT::i64) /*and trace number*/ }; computeOperandsBitWidth(N, Ops, array_lengthof(Ops)); // Do not create cycle. if (ForceMove) return CurDAG->getMachineNode(VTM::VOpMove, dl, N->getVTList(), Ops, array_lengthof(Ops)); else return CurDAG->SelectNodeTo(N, VTM::VOpMove, N->getVTList(), Ops, array_lengthof(Ops)); }
/// LowerOperation - Provide custom lowering hooks for some operations. /// SDValue AlphaTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); switch (Op.getOpcode()) { default: llvm_unreachable("Wasn't expecting to be able to lower this!"); case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::INTRINSIC_WO_CHAIN: { unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); switch (IntNo) { default: break; // Don't custom lower most intrinsics. case Intrinsic::alpha_umulh: return DAG.getNode(ISD::MULHU, dl, MVT::i64, Op.getOperand(1), Op.getOperand(2)); } } case ISD::SRL_PARTS: { SDValue ShOpLo = Op.getOperand(0); SDValue ShOpHi = Op.getOperand(1); SDValue ShAmt = Op.getOperand(2); SDValue bm = DAG.getNode(ISD::SUB, dl, MVT::i64, DAG.getConstant(64, MVT::i64), ShAmt); SDValue BMCC = DAG.getSetCC(dl, MVT::i64, bm, DAG.getConstant(0, MVT::i64), ISD::SETLE); // if 64 - shAmt <= 0 SDValue Hi_Neg = DAG.getConstant(0, MVT::i64); SDValue ShAmt_Neg = DAG.getNode(ISD::SUB, dl, MVT::i64, DAG.getConstant(0, MVT::i64), bm); SDValue Lo_Neg = DAG.getNode(ISD::SRL, dl, MVT::i64, ShOpHi, ShAmt_Neg); // else SDValue carries = DAG.getNode(ISD::SHL, dl, MVT::i64, ShOpHi, bm); SDValue Hi_Pos = DAG.getNode(ISD::SRL, dl, MVT::i64, ShOpHi, ShAmt); SDValue Lo_Pos = DAG.getNode(ISD::SRL, dl, MVT::i64, ShOpLo, ShAmt); Lo_Pos = DAG.getNode(ISD::OR, dl, MVT::i64, Lo_Pos, carries); // Merge SDValue Hi = DAG.getNode(ISD::SELECT, dl, MVT::i64, BMCC, Hi_Neg, Hi_Pos); SDValue Lo = DAG.getNode(ISD::SELECT, dl, MVT::i64, BMCC, Lo_Neg, Lo_Pos); SDValue Ops[2] = { Lo, Hi }; return DAG.getMergeValues(Ops, 2, dl); } // case ISD::SRA_PARTS: // case ISD::SHL_PARTS: case ISD::SINT_TO_FP: { assert(Op.getOperand(0).getValueType() == MVT::i64 && "Unhandled SINT_TO_FP type in custom expander!"); SDValue LD; bool isDouble = Op.getValueType() == MVT::f64; LD = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f64, Op.getOperand(0)); SDValue FP = DAG.getNode(isDouble?AlphaISD::CVTQT_:AlphaISD::CVTQS_, dl, isDouble?MVT::f64:MVT::f32, LD); return FP; } case ISD::FP_TO_SINT: { bool isDouble = Op.getOperand(0).getValueType() == MVT::f64; SDValue src = Op.getOperand(0); if (!isDouble) //Promote src = DAG.getNode(ISD::FP_EXTEND, dl, MVT::f64, src); src = DAG.getNode(AlphaISD::CVTTQ_, dl, MVT::f64, src); return DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i64, src); } case ISD::ConstantPool: { ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); Constant *C = CP->getConstVal(); SDValue CPI = DAG.getTargetConstantPool(C, MVT::i64, CP->getAlignment()); // FIXME there isn't really any debug info here SDValue Hi = DAG.getNode(AlphaISD::GPRelHi, dl, MVT::i64, CPI, DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); SDValue Lo = DAG.getNode(AlphaISD::GPRelLo, dl, MVT::i64, CPI, Hi); return Lo; } case ISD::GlobalTLSAddress: llvm_unreachable("TLS not implemented for Alpha."); case ISD::GlobalAddress: { GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op); GlobalValue *GV = GSDN->getGlobal(); SDValue GA = DAG.getTargetGlobalAddress(GV, MVT::i64, GSDN->getOffset()); // FIXME there isn't really any debug info here // if (!GV->hasWeakLinkage() && !GV->isDeclaration() && !GV->hasLinkOnceLinkage()) { if (GV->hasLocalLinkage()) { SDValue Hi = DAG.getNode(AlphaISD::GPRelHi, dl, MVT::i64, GA, DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); SDValue Lo = DAG.getNode(AlphaISD::GPRelLo, dl, MVT::i64, GA, Hi); return Lo; } else return DAG.getNode(AlphaISD::RelLit, dl, MVT::i64, GA, DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); } case ISD::ExternalSymbol: { return DAG.getNode(AlphaISD::RelLit, dl, MVT::i64, DAG.getTargetExternalSymbol(cast<ExternalSymbolSDNode>(Op) ->getSymbol(), MVT::i64), DAG.getGLOBAL_OFFSET_TABLE(MVT::i64)); } case ISD::UREM: case ISD::SREM: //Expand only on constant case if (Op.getOperand(1).getOpcode() == ISD::Constant) { EVT VT = Op.getNode()->getValueType(0); SDValue Tmp1 = Op.getNode()->getOpcode() == ISD::UREM ? BuildUDIV(Op.getNode(), DAG, NULL) : BuildSDIV(Op.getNode(), DAG, NULL); Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Op.getOperand(1)); Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Op.getOperand(0), Tmp1); return Tmp1; } //fall through case ISD::SDIV: case ISD::UDIV: if (Op.getValueType().isInteger()) { if (Op.getOperand(1).getOpcode() == ISD::Constant) return Op.getOpcode() == ISD::SDIV ? BuildSDIV(Op.getNode(), DAG, NULL) : BuildUDIV(Op.getNode(), DAG, NULL); const char* opstr = 0; switch (Op.getOpcode()) { case ISD::UREM: opstr = "__remqu"; break; case ISD::SREM: opstr = "__remq"; break; case ISD::UDIV: opstr = "__divqu"; break; case ISD::SDIV: opstr = "__divq"; break; } SDValue Tmp1 = Op.getOperand(0), Tmp2 = Op.getOperand(1), Addr = DAG.getExternalSymbol(opstr, MVT::i64); return DAG.getNode(AlphaISD::DivCall, dl, MVT::i64, Addr, Tmp1, Tmp2); } break; case ISD::VAARG: { SDValue Chain, DataPtr; LowerVAARG(Op.getNode(), Chain, DataPtr, DAG); SDValue Result; if (Op.getValueType() == MVT::i32) Result = DAG.getExtLoad(ISD::SEXTLOAD, dl, MVT::i64, Chain, DataPtr, NULL, 0, MVT::i32); else Result = DAG.getLoad(Op.getValueType(), dl, Chain, DataPtr, NULL, 0); return Result; } case ISD::VACOPY: { SDValue Chain = Op.getOperand(0); SDValue DestP = Op.getOperand(1); SDValue SrcP = Op.getOperand(2); const Value *DestS = cast<SrcValueSDNode>(Op.getOperand(3))->getValue(); const Value *SrcS = cast<SrcValueSDNode>(Op.getOperand(4))->getValue(); SDValue Val = DAG.getLoad(getPointerTy(), dl, Chain, SrcP, SrcS, 0); SDValue Result = DAG.getStore(Val.getValue(1), dl, Val, DestP, DestS, 0); SDValue NP = DAG.getNode(ISD::ADD, dl, MVT::i64, SrcP, DAG.getConstant(8, MVT::i64)); Val = DAG.getExtLoad(ISD::SEXTLOAD, dl, MVT::i64, Result, NP, NULL,0, MVT::i32); SDValue NPD = DAG.getNode(ISD::ADD, dl, MVT::i64, DestP, DAG.getConstant(8, MVT::i64)); return DAG.getTruncStore(Val.getValue(1), dl, Val, NPD, NULL, 0, MVT::i32); } case ISD::VASTART: { SDValue Chain = Op.getOperand(0); SDValue VAListP = Op.getOperand(1); const Value *VAListS = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); // vastart stores the address of the VarArgsBase and VarArgsOffset SDValue FR = DAG.getFrameIndex(VarArgsBase, MVT::i64); SDValue S1 = DAG.getStore(Chain, dl, FR, VAListP, VAListS, 0); SDValue SA2 = DAG.getNode(ISD::ADD, dl, MVT::i64, VAListP, DAG.getConstant(8, MVT::i64)); return DAG.getTruncStore(S1, dl, DAG.getConstant(VarArgsOffset, MVT::i64), SA2, NULL, 0, MVT::i32); } case ISD::RETURNADDR: return DAG.getNode(AlphaISD::GlobalRetAddr, DebugLoc::getUnknownLoc(), MVT::i64); //FIXME: implement case ISD::FRAMEADDR: break; } return SDValue(); }
/// LowerOperation - Provide custom lowering hooks for some operations. /// SDOperand AlphaTargetLowering::LowerOperation(SDOperand Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { default: assert(0 && "Wasn't expecting to be able to lower this!"); case ISD::FORMAL_ARGUMENTS: return LowerFORMAL_ARGUMENTS(Op, DAG, VarArgsBase, VarArgsOffset); case ISD::RET: return LowerRET(Op,DAG); case ISD::JumpTable: return LowerJumpTable(Op, DAG); case ISD::SINT_TO_FP: { assert(MVT::i64 == Op.getOperand(0).getValueType() && "Unhandled SINT_TO_FP type in custom expander!"); SDOperand LD; bool isDouble = MVT::f64 == Op.getValueType(); LD = DAG.getNode(ISD::BIT_CONVERT, MVT::f64, Op.getOperand(0)); SDOperand FP = DAG.getNode(isDouble?AlphaISD::CVTQT_:AlphaISD::CVTQS_, isDouble?MVT::f64:MVT::f32, LD); return FP; } case ISD::FP_TO_SINT: { bool isDouble = MVT::f64 == Op.getOperand(0).getValueType(); SDOperand src = Op.getOperand(0); if (!isDouble) //Promote src = DAG.getNode(ISD::FP_EXTEND, MVT::f64, src); src = DAG.getNode(AlphaISD::CVTTQ_, MVT::f64, src); return DAG.getNode(ISD::BIT_CONVERT, MVT::i64, src); } case ISD::ConstantPool: { ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); Constant *C = CP->getConstVal(); SDOperand CPI = DAG.getTargetConstantPool(C, MVT::i64, CP->getAlignment()); SDOperand Hi = DAG.getNode(AlphaISD::GPRelHi, MVT::i64, CPI, DAG.getNode(ISD::GLOBAL_OFFSET_TABLE, MVT::i64)); SDOperand Lo = DAG.getNode(AlphaISD::GPRelLo, MVT::i64, CPI, Hi); return Lo; } case ISD::GlobalAddress: { GlobalAddressSDNode *GSDN = cast<GlobalAddressSDNode>(Op); GlobalValue *GV = GSDN->getGlobal(); SDOperand GA = DAG.getTargetGlobalAddress(GV, MVT::i64, GSDN->getOffset()); // if (!GV->hasWeakLinkage() && !GV->isDeclaration() && !GV->hasLinkOnceLinkage()) { if (GV->hasInternalLinkage()) { SDOperand Hi = DAG.getNode(AlphaISD::GPRelHi, MVT::i64, GA, DAG.getNode(ISD::GLOBAL_OFFSET_TABLE, MVT::i64)); SDOperand Lo = DAG.getNode(AlphaISD::GPRelLo, MVT::i64, GA, Hi); return Lo; } else return DAG.getNode(AlphaISD::RelLit, MVT::i64, GA, DAG.getNode(ISD::GLOBAL_OFFSET_TABLE, MVT::i64)); } case ISD::ExternalSymbol: { return DAG.getNode(AlphaISD::RelLit, MVT::i64, DAG.getTargetExternalSymbol(cast<ExternalSymbolSDNode>(Op) ->getSymbol(), MVT::i64), DAG.getNode(ISD::GLOBAL_OFFSET_TABLE, MVT::i64)); } case ISD::UREM: case ISD::SREM: //Expand only on constant case if (Op.getOperand(1).getOpcode() == ISD::Constant) { MVT::ValueType VT = Op.Val->getValueType(0); SDOperand Tmp1 = Op.Val->getOpcode() == ISD::UREM ? BuildUDIV(Op.Val, DAG, NULL) : BuildSDIV(Op.Val, DAG, NULL); Tmp1 = DAG.getNode(ISD::MUL, VT, Tmp1, Op.getOperand(1)); Tmp1 = DAG.getNode(ISD::SUB, VT, Op.getOperand(0), Tmp1); return Tmp1; } //fall through case ISD::SDIV: case ISD::UDIV: if (MVT::isInteger(Op.getValueType())) { if (Op.getOperand(1).getOpcode() == ISD::Constant) return Op.getOpcode() == ISD::SDIV ? BuildSDIV(Op.Val, DAG, NULL) : BuildUDIV(Op.Val, DAG, NULL); const char* opstr = 0; switch (Op.getOpcode()) { case ISD::UREM: opstr = "__remqu"; break; case ISD::SREM: opstr = "__remq"; break; case ISD::UDIV: opstr = "__divqu"; break; case ISD::SDIV: opstr = "__divq"; break; } SDOperand Tmp1 = Op.getOperand(0), Tmp2 = Op.getOperand(1), Addr = DAG.getExternalSymbol(opstr, MVT::i64); return DAG.getNode(AlphaISD::DivCall, MVT::i64, Addr, Tmp1, Tmp2); } break; case ISD::VAARG: { SDOperand Chain = Op.getOperand(0); SDOperand VAListP = Op.getOperand(1); SrcValueSDNode *VAListS = cast<SrcValueSDNode>(Op.getOperand(2)); SDOperand Base = DAG.getLoad(MVT::i64, Chain, VAListP, VAListS->getValue(), VAListS->getOffset()); SDOperand Tmp = DAG.getNode(ISD::ADD, MVT::i64, VAListP, DAG.getConstant(8, MVT::i64)); SDOperand Offset = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Base.getValue(1), Tmp, NULL, 0, MVT::i32); SDOperand DataPtr = DAG.getNode(ISD::ADD, MVT::i64, Base, Offset); if (MVT::isFloatingPoint(Op.getValueType())) { //if fp && Offset < 6*8, then subtract 6*8 from DataPtr SDOperand FPDataPtr = DAG.getNode(ISD::SUB, MVT::i64, DataPtr, DAG.getConstant(8*6, MVT::i64)); SDOperand CC = DAG.getSetCC(MVT::i64, Offset, DAG.getConstant(8*6, MVT::i64), ISD::SETLT); DataPtr = DAG.getNode(ISD::SELECT, MVT::i64, CC, FPDataPtr, DataPtr); } SDOperand NewOffset = DAG.getNode(ISD::ADD, MVT::i64, Offset, DAG.getConstant(8, MVT::i64)); SDOperand Update = DAG.getTruncStore(Offset.getValue(1), NewOffset, Tmp, NULL, 0, MVT::i32); SDOperand Result; if (Op.getValueType() == MVT::i32) Result = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Update, DataPtr, NULL, 0, MVT::i32); else Result = DAG.getLoad(Op.getValueType(), Update, DataPtr, NULL, 0); return Result; } case ISD::VACOPY: { SDOperand Chain = Op.getOperand(0); SDOperand DestP = Op.getOperand(1); SDOperand SrcP = Op.getOperand(2); SrcValueSDNode *DestS = cast<SrcValueSDNode>(Op.getOperand(3)); SrcValueSDNode *SrcS = cast<SrcValueSDNode>(Op.getOperand(4)); SDOperand Val = DAG.getLoad(getPointerTy(), Chain, SrcP, SrcS->getValue(), SrcS->getOffset()); SDOperand Result = DAG.getStore(Val.getValue(1), Val, DestP, DestS->getValue(), DestS->getOffset()); SDOperand NP = DAG.getNode(ISD::ADD, MVT::i64, SrcP, DAG.getConstant(8, MVT::i64)); Val = DAG.getExtLoad(ISD::SEXTLOAD, MVT::i64, Result, NP, NULL,0, MVT::i32); SDOperand NPD = DAG.getNode(ISD::ADD, MVT::i64, DestP, DAG.getConstant(8, MVT::i64)); return DAG.getTruncStore(Val.getValue(1), Val, NPD, NULL, 0, MVT::i32); } case ISD::VASTART: { SDOperand Chain = Op.getOperand(0); SDOperand VAListP = Op.getOperand(1); SrcValueSDNode *VAListS = cast<SrcValueSDNode>(Op.getOperand(2)); // vastart stores the address of the VarArgsBase and VarArgsOffset SDOperand FR = DAG.getFrameIndex(VarArgsBase, MVT::i64); SDOperand S1 = DAG.getStore(Chain, FR, VAListP, VAListS->getValue(), VAListS->getOffset()); SDOperand SA2 = DAG.getNode(ISD::ADD, MVT::i64, VAListP, DAG.getConstant(8, MVT::i64)); return DAG.getTruncStore(S1, DAG.getConstant(VarArgsOffset, MVT::i64), SA2, NULL, 0, MVT::i32); } case ISD::RETURNADDR: return DAG.getNode(AlphaISD::GlobalRetAddr, MVT::i64); //FIXME: implement case ISD::FRAMEADDR: break; } return SDOperand(); }
SDValue Cpu0TargetLowering:: LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const { // If the relocation model is PIC, use the General Dynamic TLS Model or // Local Dynamic TLS model, otherwise use the Initial Exec or // Local Exec TLS Model. GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op); DebugLoc dl = GA->getDebugLoc(); const GlobalValue *GV = GA->getGlobal(); EVT PtrVT = getPointerTy(); if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { // General Dynamic TLS Model bool LocalDynamic = GV->hasInternalLinkage(); unsigned Flag = LocalDynamic ? Cpu0II::MO_TLSLDM :Cpu0II::MO_TLSGD; SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Flag); SDValue Argument = DAG.getNode(Cpu0ISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT), TGA); unsigned PtrSize = PtrVT.getSizeInBits(); IntegerType *PtrTy = Type::getIntNTy(*DAG.getContext(), PtrSize); SDValue TlsGetAddr = DAG.getExternalSymbol("__tls_get_addr", PtrVT); ArgListTy Args; ArgListEntry Entry; Entry.Node = Argument; Entry.Ty = PtrTy; Args.push_back(Entry); std::pair<SDValue, SDValue> CallResult = LowerCallTo(DAG.getEntryNode(), PtrTy, false, false, false, false, 0, CallingConv::C, /*isTailCall=*/false, /*doesNotRet=*/false, /*isReturnValueUsed=*/true, TlsGetAddr, Args, DAG, dl); SDValue Ret = CallResult.first; if (!LocalDynamic) return Ret; SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Cpu0II::MO_DTPREL_HI); SDValue Hi = DAG.getNode(Cpu0ISD::Hi, dl, PtrVT, TGAHi); SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Cpu0II::MO_DTPREL_LO); SDValue Lo = DAG.getNode(Cpu0ISD::Lo, dl, PtrVT, TGALo); SDValue Add = DAG.getNode(ISD::ADD, dl, PtrVT, Hi, Ret); return DAG.getNode(ISD::ADD, dl, PtrVT, Add, Lo); } SDValue Offset; if (GV->isDeclaration()) { // Initial Exec TLS Model SDValue TGA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Cpu0II::MO_GOTTPREL); TGA = DAG.getNode(Cpu0ISD::Wrapper, dl, PtrVT, GetGlobalReg(DAG, PtrVT), TGA); Offset = DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), TGA, MachinePointerInfo(), false, false, false, 0); } else { // Local Exec TLS Model SDValue TGAHi = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Cpu0II::MO_TPREL_HI); SDValue TGALo = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, Cpu0II::MO_TPREL_LO); SDValue Hi = DAG.getNode(Cpu0ISD::Hi, dl, PtrVT, TGAHi); SDValue Lo = DAG.getNode(Cpu0ISD::Lo, dl, PtrVT, TGALo); Offset = DAG.getNode(ISD::ADD, dl, PtrVT, Hi, Lo); } SDValue ThreadPointer = DAG.getNode(Cpu0ISD::ThreadPointer, dl, PtrVT); return DAG.getNode(ISD::ADD, dl, PtrVT, ThreadPointer, Offset); }
// LowerCCCCallTo - functions arguments are copied from virtual regs to // (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. SDValue LanaiTargetLowering::LowerCCCCallTo( SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool IsVarArg, bool IsTailCall, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SmallVectorImpl<ISD::InputArg> &Ins, SDLoc DL, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs, *DAG.getContext()); GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee); MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); NumFixedArgs = 0; if (IsVarArg && G) { const Function *CalleeFn = dyn_cast<Function>(G->getGlobal()); if (CalleeFn) NumFixedArgs = CalleeFn->getFunctionType()->getNumParams(); } if (NumFixedArgs) CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_VarArg); else { if (CallConv == CallingConv::Fast) CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32_Fast); else CCInfo.AnalyzeCallOperands(Outs, CC_Lanai32); } // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); // 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(); unsigned Align = Flags.getByValAlign(); int FI = MFI->CreateStackObject(Size, Align, false); SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); SDValue SizeNode = DAG.getConstant(Size, DL, MVT::i32); Chain = DAG.getMemcpy(Chain, DL, FIPtr, Arg, SizeNode, Align, /*IsVolatile=*/false, /*AlwaysInline=*/false, /*IsTailCall=*/false, MachinePointerInfo(), MachinePointerInfo()); ByValArgs.push_back(FIPtr); } Chain = DAG.getCALLSEQ_START( Chain, DAG.getConstant(NumBytes, DL, getPointerTy(DAG.getDataLayout()), true), DL); SmallVector<std::pair<unsigned, SDValue>, 4> RegsToPass; SmallVector<SDValue, 12> MemOpChains; SDValue StackPtr; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned I = 0, J = 0, E = ArgLocs.size(); I != E; ++I) { CCValAssign &VA = ArgLocs[I]; SDValue Arg = OutVals[I]; ISD::ArgFlagsTy Flags = Outs[I].Flags; // Promote the value if needed. switch (VA.getLocInfo()) { case CCValAssign::Full: break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg); break; case CCValAssign::ZExt: Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg); break; case CCValAssign::AExt: Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg); break; default: llvm_unreachable("Unknown loc info!"); } // Use local copy if it is a byval arg. if (Flags.isByVal()) Arg = ByValArgs[J++]; // Arguments that can be passed on register must be kept at RegsToPass // vector if (VA.isRegLoc()) { RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); } else { assert(VA.isMemLoc()); if (StackPtr.getNode() == 0) StackPtr = DAG.getCopyFromReg(Chain, DL, Lanai::SP, getPointerTy(DAG.getDataLayout())); SDValue PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(DAG.getDataLayout()), StackPtr, DAG.getIntPtrConstant(VA.getLocMemOffset(), DL)); MemOpChains.push_back(DAG.getStore( Chain, DL, Arg, PtrOff, MachinePointerInfo(), false, false, 0)); } } // Transform all store nodes into one single node because all store nodes are // independent of each other. if (!MemOpChains.empty()) Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, ArrayRef<SDValue>(&MemOpChains[0], MemOpChains.size())); SDValue InFlag; // Build a sequence of copy-to-reg nodes chained together with token chain and // flag operands which copy the outgoing args into registers. The InFlag in // necessary since all emitted instructions must be stuck together. for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) { Chain = DAG.getCopyToReg(Chain, DL, RegsToPass[I].first, RegsToPass[I].second, InFlag); InFlag = Chain.getValue(1); } // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. uint8_t OpFlag = LanaiII::MO_NO_FLAG; if (G) { Callee = DAG.getTargetGlobalAddress( G->getGlobal(), DL, getPointerTy(DAG.getDataLayout()), 0, OpFlag); } else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) { Callee = DAG.getTargetExternalSymbol( E->getSymbol(), getPointerTy(DAG.getDataLayout()), OpFlag); } // Returns a chain & a flag for retval copy to use. SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); SmallVector<SDValue, 8> Ops; Ops.push_back(Chain); Ops.push_back(Callee); // Add a register mask operand representing the call-preserved registers. // TODO: Should return-twice functions be handled? const uint32_t *Mask = TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv); assert(Mask && "Missing call preserved mask for calling convention"); Ops.push_back(DAG.getRegisterMask(Mask)); // Add argument registers to the end of the list so that they are // known live into the call. for (unsigned I = 0, E = RegsToPass.size(); I != E; ++I) Ops.push_back(DAG.getRegister(RegsToPass[I].first, RegsToPass[I].second.getValueType())); if (InFlag.getNode()) Ops.push_back(InFlag); Chain = DAG.getNode(LanaiISD::CALL, DL, NodeTys, ArrayRef<SDValue>(&Ops[0], Ops.size())); InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. Chain = DAG.getCALLSEQ_END( Chain, DAG.getConstant(NumBytes, DL, getPointerTy(DAG.getDataLayout()), true), DAG.getConstant(0, DL, getPointerTy(DAG.getDataLayout()), true), InFlag, DL); InFlag = Chain.getValue(1); // Handle result values, copying them out of physregs into vregs that we // return. return LowerCallResult(Chain, InFlag, CallConv, IsVarArg, Ins, DL, DAG, InVals); }