/// Try to find existing copies of the incoming values in stack slots used for /// statepoint spilling. If we can find a spill slot for the incoming value, /// mark that slot as allocated, and reuse the same slot for this safepoint. /// This helps to avoid series of loads and stores that only serve to reshuffle /// values on the stack between calls. static void reservePreviousStackSlotForValue(const Value *IncomingValue, SelectionDAGBuilder &Builder) { SDValue Incoming = Builder.getValue(IncomingValue); if (isa<ConstantSDNode>(Incoming) || isa<FrameIndexSDNode>(Incoming)) { // We won't need to spill this, so no need to check for previously // allocated stack slots return; } SDValue OldLocation = Builder.StatepointLowering.getLocation(Incoming); if (OldLocation.getNode()) // Duplicates in input return; const int LookUpDepth = 6; Optional<int> Index = findPreviousSpillSlot(IncomingValue, Builder, LookUpDepth); if (!Index.hasValue()) return; const auto &StatepointSlots = Builder.FuncInfo.StatepointStackSlots; auto SlotIt = find(StatepointSlots, *Index); assert(SlotIt != StatepointSlots.end() && "Value spilled to the unknown stack slot"); // This is one of our dedicated lowering slots const int Offset = std::distance(StatepointSlots.begin(), SlotIt); if (Builder.StatepointLowering.isStackSlotAllocated(Offset)) { // stack slot already assigned to someone else, can't use it! // TODO: currently we reserve space for gc arguments after doing // normal allocation for deopt arguments. We should reserve for // _all_ deopt and gc arguments, then start allocating. This // will prevent some moves being inserted when vm state changes, // but gc state doesn't between two calls. return; } // Reserve this stack slot Builder.StatepointLowering.reserveStackSlot(Offset); // Cache this slot so we find it when going through the normal // assignment loop. SDValue Loc = Builder.DAG.getTargetFrameIndex(*Index, Incoming.getValueType()); Builder.StatepointLowering.setLocation(Incoming, Loc); }
// This function expands mips intrinsic nodes which have 64-bit input operands // or output values. // // out64 = intrinsic-node in64 // => // lo = copy (extract-element (in64, 0)) // hi = copy (extract-element (in64, 1)) // mips-specific-node // v0 = copy lo // v1 = copy hi // out64 = merge-values (v0, v1) // static SDValue lowerDSPIntr(SDValue Op, SelectionDAG &DAG, unsigned Opc) { DebugLoc DL = Op.getDebugLoc(); bool HasChainIn = Op->getOperand(0).getValueType() == MVT::Other; SmallVector<SDValue, 3> Ops; unsigned OpNo = 0; // See if Op has a chain input. if (HasChainIn) Ops.push_back(Op->getOperand(OpNo++)); // The next operand is the intrinsic opcode. assert(Op->getOperand(OpNo).getOpcode() == ISD::TargetConstant); // See if the next operand has type i64. SDValue Opnd = Op->getOperand(++OpNo), In64; if (Opnd.getValueType() == MVT::i64) In64 = initAccumulator(Opnd, DL, DAG); else Ops.push_back(Opnd); // Push the remaining operands. for (++OpNo ; OpNo < Op->getNumOperands(); ++OpNo) Ops.push_back(Op->getOperand(OpNo)); // Add In64 to the end of the list. if (In64.getNode()) Ops.push_back(In64); // Scan output. SmallVector<EVT, 2> ResTys; for (SDNode::value_iterator I = Op->value_begin(), E = Op->value_end(); I != E; ++I) ResTys.push_back((*I == MVT::i64) ? MVT::Untyped : *I); // Create node. SDValue Val = DAG.getNode(Opc, DL, ResTys, &Ops[0], Ops.size()); SDValue Out = (ResTys[0] == MVT::Untyped) ? extractLOHI(Val, DL, DAG) : Val; if (!HasChainIn) return Out; assert(Val->getValueType(1) == MVT::Other); SDValue Vals[] = { Out, SDValue(Val.getNode(), 1) }; return DAG.getMergeValues(Vals, 2, DL); }
SDValue BPFTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, const SDLoc &DL, SelectionDAG &DAG) const { unsigned Opc = BPFISD::RET_FLAG; // CCValAssign - represent the assignment of the return value to a location SmallVector<CCValAssign, 16> RVLocs; MachineFunction &MF = DAG.getMachineFunction(); // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, *DAG.getContext()); if (MF.getFunction()->getReturnType()->isAggregateType()) { fail(DL, DAG, "only integer returns supported"); return DAG.getNode(Opc, DL, MVT::Other, Chain); } // Analize return values. CCInfo.AnalyzeReturn(Outs, RetCC_BPF64); SDValue Flag; SmallVector<SDValue, 4> RetOps(1, Chain); // Copy the result values into the output registers. for (unsigned i = 0; i != RVLocs.size(); ++i) { CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVals[i], Flag); // Guarantee that all emitted copies are stuck together, // avoiding something bad. Flag = Chain.getValue(1); RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); } RetOps[0] = Chain; // Update chain. // Add the flag if we have it. if (Flag.getNode()) RetOps.push_back(Flag); return DAG.getNode(Opc, DL, MVT::Other, RetOps); }
SDValue AMDGPUTargetLowering::LowerSDIV(SDValue Op, SelectionDAG &DAG) const { EVT OVT = Op.getValueType(); SDValue DST; if (OVT.getScalarType() == MVT::i64) { DST = LowerSDIV64(Op, DAG); } else if (OVT.getScalarType() == MVT::i32) { DST = LowerSDIV32(Op, DAG); } else if (OVT.getScalarType() == MVT::i16 || OVT.getScalarType() == MVT::i8) { DST = LowerSDIV24(Op, DAG); } else { DST = SDValue(Op.getNode(), 0); } return DST; }
SDValue BlackfinTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: Op.getNode()->dump(); llvm_unreachable("Should not custom lower this!"); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::GlobalTLSAddress: llvm_unreachable("TLS not implemented for Blackfin."); case ISD::JumpTable: return LowerJumpTable(Op, DAG); // Frame & Return address. Currently unimplemented case ISD::FRAMEADDR: return SDValue(); case ISD::RETURNADDR: return SDValue(); case ISD::ADDE: case ISD::SUBE: return LowerADDE(Op, DAG); } }
bool AMDGPUDAGToDAGISel::SelectU24(SDValue Op, SDValue &U24) { APInt KnownZero; APInt KnownOne; CurDAG->ComputeMaskedBits(Op, KnownZero, KnownOne); assert (Op.getValueType() == MVT::i32); // ANY_EXTEND and EXTLOAD operations can only be done on types smaller than // i32. These smaller types are legal to use with the i24 instructions. if ((KnownZero & APInt(KnownZero.getBitWidth(), 0xFF000000)) == 0xFF000000 || Op.getOpcode() == ISD::ANY_EXTEND || ISD::isEXTLoad(Op.getNode())) { U24 = SimplifyI24(Op); return true; } return false; }
// Select constant vector splats whose value is a power of 2. // // In addition to the requirements of selectVSplat(), this function returns // true and sets Imm if: // * The splat value is the same width as the elements of the vector // * The splat value is a power of two. // // This function looks through ISD::BITCAST nodes. // TODO: This might not be appropriate for big-endian MSA since BITCAST is // sometimes a shuffle in big-endian mode. bool MipsSEDAGToDAGISel::selectVSplatUimmPow2(SDValue N, SDValue &Imm) const { APInt ImmValue; EVT EltTy = N->getValueType(0).getVectorElementType(); if (N->getOpcode() == ISD::BITCAST) N = N->getOperand(0); if (selectVSplat (N.getNode(), ImmValue) && ImmValue.getBitWidth() == EltTy.getSizeInBits()) { int32_t Log2 = ImmValue.exactLogBase2(); if (Log2 != -1) { Imm = CurDAG->getTargetConstant(Log2, EltTy); return true; } } return false; }
// Select constant vector splats whose value only has a consecutive sequence // of right-most bits set (e.g. 0b00...0011...11). // // In addition to the requirements of selectVSplat(), this function returns // true and sets Imm if: // * The splat value is the same width as the elements of the vector // * The splat value is a consecutive sequence of right-most bits. // // This function looks through ISD::BITCAST nodes. // TODO: This might not be appropriate for big-endian MSA since BITCAST is // sometimes a shuffle in big-endian mode. bool MipsSEDAGToDAGISel::selectVSplatMaskR(SDValue N, SDValue &Imm) const { APInt ImmValue; EVT EltTy = N->getValueType(0).getVectorElementType(); if (N->getOpcode() == ISD::BITCAST) N = N->getOperand(0); if (selectVSplat(N.getNode(), ImmValue) && ImmValue.getBitWidth() == EltTy.getSizeInBits()) { // Extract the run of set bits starting with bit zero, and test that the // result is the same as the original value if (ImmValue == (ImmValue & ~(ImmValue + 1))) { Imm = CurDAG->getTargetConstant(ImmValue.countPopulation(), EltTy); return true; } } return false; }
SDValue MSP430TargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); SDNode* N = Op.getNode(); EVT VT = Op.getValueType(); DebugLoc dl = N->getDebugLoc(); // Expand non-constant shifts to loops: if (!isa<ConstantSDNode>(N->getOperand(1))) switch (Opc) { default: assert(0 && "Invalid shift opcode!"); case ISD::SHL: return DAG.getNode(MSP430ISD::SHL, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRA: return DAG.getNode(MSP430ISD::SRA, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRL: return DAG.getNode(MSP430ISD::SRL, dl, VT, N->getOperand(0), N->getOperand(1)); } uint64_t ShiftAmount = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); // Expand the stuff into sequence of shifts. // FIXME: for some shift amounts this might be done better! // E.g.: foo >> (8 + N) => sxt(swpb(foo)) >> N SDValue Victim = N->getOperand(0); if (Opc == ISD::SRL && ShiftAmount) { // Emit a special goodness here: // srl A, 1 => clrc; rrc A Victim = DAG.getNode(MSP430ISD::RRC, dl, VT, Victim); ShiftAmount -= 1; } while (ShiftAmount--) Victim = DAG.getNode((Opc == ISD::SHL ? MSP430ISD::RLA : MSP430ISD::RRA), dl, VT, Victim); return Victim; }
SDValue SparcTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, DebugLoc dl, SelectionDAG &DAG) const { // CCValAssign - represent the assignment of the return value to locations. SmallVector<CCValAssign, 16> RVLocs; // CCState - Info about the registers and stack slot. CCState CCInfo(CallConv, isVarArg, DAG.getTarget(), RVLocs, *DAG.getContext()); // Analize return values. CCInfo.AnalyzeReturn(Outs, RetCC_Sparc32); // If this is the first return lowered for this function, add the regs to the // liveout set for the function. if (DAG.getMachineFunction().getRegInfo().liveout_empty()) { for (unsigned i = 0; i != RVLocs.size(); ++i) if (RVLocs[i].isRegLoc()) DAG.getMachineFunction().getRegInfo().addLiveOut(RVLocs[i].getLocReg()); } SDValue Flag; // Copy the result values into the output registers. for (unsigned i = 0; i != RVLocs.size(); ++i) { CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), OutVals[i], Flag); // Guarantee that all emitted copies are stuck together with flags. Flag = Chain.getValue(1); } if (Flag.getNode()) return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain, Flag); return DAG.getNode(SPISD::RET_FLAG, dl, MVT::Other, Chain); }
SDValue AVRTargetLowering::LowerShifts(SDValue Op, SelectionDAG &DAG) const { unsigned Opc = Op.getOpcode(); SDNode* N = Op.getNode(); EVT VT = Op.getValueType(); DebugLoc dl = N->getDebugLoc(); // Expand non-constant shifts to loops: if (!isa<ConstantSDNode>(N->getOperand(1))) switch (Opc) { default: assert(0 && "Invalid shift opcode!"); case ISD::SHL: return DAG.getNode(AVRISD::SHL, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRA: return DAG.getNode(AVRISD::SRA, dl, VT, N->getOperand(0), N->getOperand(1)); case ISD::SRL: return DAG.getNode(AVRISD::SRL, dl, VT, N->getOperand(0), N->getOperand(1)); } uint64_t ShiftAmount = N->getConstantOperandVal(1); // Expand the stuff into sequence of shifts. // FIXME: for some shift amounts this might be done better! // E.g.: foo >> (8 + N) => sxt(swpb(foo)) >> N SDValue Victim = N->getOperand(0); unsigned int TargetOpcode = 0; switch(Opc) { case ISD::SHL: TargetOpcode = AVRISD::SHLC; break; case ISD::SRA: TargetOpcode = AVRISD::SRAC; break; case ISD::SRL: TargetOpcode = AVRISD::SRLC; break; } while (ShiftAmount--) Victim = DAG.getNode(TargetOpcode, dl, VT, Victim); return Victim; }
/// getVR - Return the virtual register corresponding to the specified result /// of the specified node. unsigned ScheduleDAGSDNodes::getVR(SDValue Op, DenseMap<SDValue, unsigned> &VRBaseMap) { if (Op.isMachineOpcode() && Op.getMachineOpcode() == TargetInstrInfo::IMPLICIT_DEF) { // Add an IMPLICIT_DEF instruction before every use. unsigned VReg = getDstOfOnlyCopyToRegUse(Op.getNode(), Op.getResNo()); // IMPLICIT_DEF can produce any type of result so its TargetInstrDesc // does not include operand register class info. if (!VReg) { const TargetRegisterClass *RC = TLI->getRegClassFor(Op.getValueType()); VReg = MRI.createVirtualRegister(RC); } BuildMI(BB, Op.getDebugLoc(), TII->get(TargetInstrInfo::IMPLICIT_DEF),VReg); return VReg; } DenseMap<SDValue, unsigned>::iterator I = VRBaseMap.find(Op); assert(I != VRBaseMap.end() && "Node emitted out of order - late"); return I->second; }
// Select constant vector splats. // // In addition to the requirements of selectVSplat(), this function returns // true and sets Imm if: // * The splat value is the same width as the elements of the vector // * The splat value fits in an integer with the specified signed-ness and // width. // // This function looks through ISD::BITCAST nodes. // TODO: This might not be appropriate for big-endian MSA since BITCAST is // sometimes a shuffle in big-endian mode. // // It's worth noting that this function is not used as part of the selection // of ldi.[bhwd] since it does not permit using the wrong-typed ldi.[bhwd] // instruction to achieve the desired bit pattern. ldi.[bhwd] is selected in // MipsSEDAGToDAGISel::selectNode. bool MipsSEDAGToDAGISel:: selectVSplatCommon(SDValue N, SDValue &Imm, bool Signed, unsigned ImmBitSize) const { APInt ImmValue; EVT EltTy = N->getValueType(0).getVectorElementType(); if (N->getOpcode() == ISD::BITCAST) N = N->getOperand(0); if (selectVSplat (N.getNode(), ImmValue) && ImmValue.getBitWidth() == EltTy.getSizeInBits()) { if (( Signed && ImmValue.isSignedIntN(ImmBitSize)) || (!Signed && ImmValue.isIntN(ImmBitSize))) { Imm = CurDAG->getTargetConstant(ImmValue, EltTy); return true; } } return false; }
bool AMDGPUDAGToDAGISel::FoldOperand(SDValue &Src, SDValue &Sel, SDValue &Neg, SDValue &Abs, const R600InstrInfo *TII) { switch (Src.getOpcode()) { case ISD::FNEG: Src = Src.getOperand(0); Neg = CurDAG->getTargetConstant(1, MVT::i32); return true; case ISD::FABS: if (!Abs.getNode()) return false; Src = Src.getOperand(0); Abs = CurDAG->getTargetConstant(1, MVT::i32); return true; case ISD::BITCAST: Src = Src.getOperand(0); return true; default: return false; } }
// Helper for AddGlue to clone node operands. static void CloneNodeWithValues(SDNode *N, SelectionDAG *DAG, ArrayRef<EVT> VTs, SDValue ExtraOper = SDValue()) { SmallVector<SDValue, 8> Ops(N->op_begin(), N->op_end()); if (ExtraOper.getNode()) Ops.push_back(ExtraOper); SDVTList VTList = DAG->getVTList(VTs); MachineSDNode *MN = dyn_cast<MachineSDNode>(N); // Store memory references. SmallVector<MachineMemOperand *, 2> MMOs; if (MN) MMOs.assign(MN->memoperands_begin(), MN->memoperands_end()); DAG->MorphNodeTo(N, N->getOpcode(), VTList, Ops); // Reset the memory references if (MN) DAG->setNodeMemRefs(MN, MMOs); }
static void AddGlue(SDNode *N, SDValue Glue, bool AddGlue, SelectionDAG *DAG) { SmallVector<EVT, 4> VTs; SDNode *GlueDestNode = Glue.getNode(); // Don't add glue from a node to itself. if (GlueDestNode == N) return; // Don't add glue to something that already has it, either as a use or value. if (N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue || N->getValueType(N->getNumValues() - 1) == MVT::Glue) { return; } for (unsigned I = 0, E = N->getNumValues(); I != E; ++I) VTs.push_back(N->getValueType(I)); if (AddGlue) VTs.push_back(MVT::Glue); SmallVector<SDValue, 4> Ops; for (unsigned I = 0, E = N->getNumOperands(); I != E; ++I) Ops.push_back(N->getOperand(I)); if (GlueDestNode) Ops.push_back(Glue); SDVTList VTList = DAG->getVTList(&VTs[0], VTs.size()); MachineSDNode::mmo_iterator Begin = 0, End = 0; MachineSDNode *MN = dyn_cast<MachineSDNode>(N); // Store memory references. if (MN) { Begin = MN->memoperands_begin(); End = MN->memoperands_end(); } DAG->MorphNodeTo(N, N->getOpcode(), VTList, &Ops[0], Ops.size()); // Reset the memory references if (MN) MN->setMemRefs(Begin, End); }
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for /// inline asm expressions. bool NVPTXDAGToDAGISel::SelectInlineAsmMemoryOperand( const SDValue &Op, char ConstraintCode, std::vector<SDValue> &OutOps) { SDValue Op0, Op1; switch (ConstraintCode) { default: return true; case 'm': // memory if (SelectDirectAddr(Op, Op0)) { OutOps.push_back(Op0); OutOps.push_back(CurDAG->getTargetConstant(0, MVT::i32)); return false; } if (SelectADDRri(Op.getNode(), Op, Op0, Op1)) { OutOps.push_back(Op0); OutOps.push_back(Op1); return false; } break; } return true; }
static void AddFlags(SDNode *N, SDValue Flag, bool AddFlag, SelectionDAG *DAG) { SmallVector<EVT, 4> VTs; SDNode *FlagDestNode = Flag.getNode(); // Don't add a flag from a node to itself. if (FlagDestNode == N) return; // Don't add a flag to something which already has a flag. if (N->getValueType(N->getNumValues() - 1) == MVT::Flag) return; for (unsigned I = 0, E = N->getNumValues(); I != E; ++I) VTs.push_back(N->getValueType(I)); if (AddFlag) VTs.push_back(MVT::Flag); SmallVector<SDValue, 4> Ops; for (unsigned I = 0, E = N->getNumOperands(); I != E; ++I) Ops.push_back(N->getOperand(I)); if (FlagDestNode) Ops.push_back(Flag); SDVTList VTList = DAG->getVTList(&VTs[0], VTs.size()); MachineSDNode::mmo_iterator Begin = 0, End = 0; MachineSDNode *MN = dyn_cast<MachineSDNode>(N); // Store memory references. if (MN) { Begin = MN->memoperands_begin(); End = MN->memoperands_end(); } DAG->MorphNodeTo(N, N->getOpcode(), VTList, &Ops[0], Ops.size()); // Reset the memory references if (MN) MN->setMemRefs(Begin, End); }
// Helper for AddGlue to clone node operands. static void CloneNodeWithValues(SDNode *N, SelectionDAG *DAG, ArrayRef<EVT> VTs, SDValue ExtraOper = SDValue()) { SmallVector<SDValue, 8> Ops(N->op_begin(), N->op_end()); if (ExtraOper.getNode()) Ops.push_back(ExtraOper); SDVTList VTList = DAG->getVTList(VTs); MachineSDNode::mmo_iterator Begin = nullptr, End = nullptr; MachineSDNode *MN = dyn_cast<MachineSDNode>(N); // Store memory references. if (MN) { Begin = MN->memoperands_begin(); End = MN->memoperands_end(); } DAG->MorphNodeTo(N, N->getOpcode(), VTList, Ops); // Reset the memory references if (MN) MN->setMemRefs(Begin, End); }
static bool AddGlue(SDNode *N, SDValue Glue, bool AddGlue, SelectionDAG *DAG) { SDNode *GlueDestNode = Glue.getNode(); // Don't add glue from a node to itself. if (GlueDestNode == N) return false; // Don't add a glue operand to something that already uses glue. if (GlueDestNode && N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Glue) { return false; } // Don't add glue to something that already has a glue value. if (N->getValueType(N->getNumValues() - 1) == MVT::Glue) return false; SmallVector<EVT, 4> VTs(N->value_begin(), N->value_end()); if (AddGlue) VTs.push_back(MVT::Glue); CloneNodeWithValues(N, DAG, VTs, Glue); return true; }
SDValue Y86TargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, SDLoc dl, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); // Gather info about the return values. SmallVector<CCValAssign, 16> RVLocs; CCState CCInfo(CallConv, isVarArg, MF, RVLocs, *DAG.getContext()); CCInfo.AnalyzeReturn(Outs, RetCC_Y86); SDValue Flag; SmallVector<SDValue, 6> RetOps(1, Chain); // Operand 0 is the chain. // Copy the result values into the output registers. for (unsigned i = 0; i != RVLocs.size(); ++i) { CCValAssign &VA = RVLocs[i]; assert(VA.isRegLoc() && "Can only return in registers!"); SDValue ValToCopy = OutVals[i]; Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), ValToCopy, Flag); Flag = Chain.getValue(1); // Copies are glued together with flags. RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT())); } RetOps[0] = Chain; // Update the chain. // Add the flag if we have it. if (Flag.getNode()) RetOps.push_back(Flag); return DAG.getNode(Y86ISD::RET_FLAG, dl, MVT::Other, RetOps); }
void SelectionDAGBuilder::visitGCResult(const CallInst &CI) { // The result value of the gc_result is simply the result of the actual // call. We've already emitted this, so just grab the value. Instruction *I = cast<Instruction>(CI.getArgOperand(0)); assert(isStatepoint(I) && "first argument must be a statepoint token"); if (isa<InvokeInst>(I)) { // For invokes we should have stored call result in a virtual register. // We can not use default getValue() functionality to copy value from this // register because statepoint and actuall call return types can be // different, and getValue() will use CopyFromReg of the wrong type, // which is always i32 in our case. PointerType *CalleeType = cast<PointerType>( ImmutableStatepoint(I).getCalledValue()->getType()); Type *RetTy = cast<FunctionType>(CalleeType->getElementType())->getReturnType(); SDValue CopyFromReg = getCopyFromRegs(I, RetTy); assert(CopyFromReg.getNode()); setValue(&CI, CopyFromReg); } else { setValue(&CI, getValue(I)); } }
/// Do extensive, expensive, sanity checking. void DAGTypeLegalizer::PerformExpensiveChecks() { // If a node is not processed, then none of its values should be mapped by any // of PromotedIntegers, ExpandedIntegers, ..., ReplacedValues. // If a node is processed, then each value with an illegal type must be mapped // by exactly one of PromotedIntegers, ExpandedIntegers, ..., ReplacedValues. // Values with a legal type may be mapped by ReplacedValues, but not by any of // the other maps. // Note that these invariants may not hold momentarily when processing a node: // the node being processed may be put in a map before being marked Processed. // Note that it is possible to have nodes marked NewNode in the DAG. This can // occur in two ways. Firstly, a node may be created during legalization but // never passed to the legalization core. This is usually due to the implicit // folding that occurs when using the DAG.getNode operators. Secondly, a new // node may be passed to the legalization core, but when analyzed may morph // into a different node, leaving the original node as a NewNode in the DAG. // A node may morph if one of its operands changes during analysis. Whether // it actually morphs or not depends on whether, after updating its operands, // it is equivalent to an existing node: if so, it morphs into that existing // node (CSE). An operand can change during analysis if the operand is a new // node that morphs, or it is a processed value that was mapped to some other // value (as recorded in ReplacedValues) in which case the operand is turned // into that other value. If a node morphs then the node it morphed into will // be used instead of it for legalization, however the original node continues // to live on in the DAG. // The conclusion is that though there may be nodes marked NewNode in the DAG, // all uses of such nodes are also marked NewNode: the result is a fungus of // NewNodes growing on top of the useful nodes, and perhaps using them, but // not used by them. // If a value is mapped by ReplacedValues, then it must have no uses, except // by nodes marked NewNode (see above). // The final node obtained by mapping by ReplacedValues is not marked NewNode. // Note that ReplacedValues should be applied iteratively. // Note that the ReplacedValues map may also map deleted nodes (by iterating // over the DAG we never dereference deleted nodes). This means that it may // also map nodes marked NewNode if the deallocated memory was reallocated as // another node, and that new node was not seen by the LegalizeTypes machinery // (for example because it was created but not used). In general, we cannot // distinguish between new nodes and deleted nodes. SmallVector<SDNode*, 16> NewNodes; for (SDNode &Node : DAG.allnodes()) { // Remember nodes marked NewNode - they are subject to extra checking below. if (Node.getNodeId() == NewNode) NewNodes.push_back(&Node); for (unsigned i = 0, e = Node.getNumValues(); i != e; ++i) { SDValue Res(&Node, i); EVT VT = Res.getValueType(); bool Failed = false; unsigned Mapped = 0; if (ReplacedValues.find(Res) != ReplacedValues.end()) { Mapped |= 1; // Check that remapped values are only used by nodes marked NewNode. for (SDNode::use_iterator UI = Node.use_begin(), UE = Node.use_end(); UI != UE; ++UI) if (UI.getUse().getResNo() == i) assert(UI->getNodeId() == NewNode && "Remapped value has non-trivial use!"); // Check that the final result of applying ReplacedValues is not // marked NewNode. SDValue NewVal = ReplacedValues[Res]; DenseMap<SDValue, SDValue>::iterator I = ReplacedValues.find(NewVal); while (I != ReplacedValues.end()) { NewVal = I->second; I = ReplacedValues.find(NewVal); } assert(NewVal.getNode()->getNodeId() != NewNode && "ReplacedValues maps to a new node!"); } if (PromotedIntegers.find(Res) != PromotedIntegers.end()) Mapped |= 2; if (SoftenedFloats.find(Res) != SoftenedFloats.end()) Mapped |= 4; if (ScalarizedVectors.find(Res) != ScalarizedVectors.end()) Mapped |= 8; if (ExpandedIntegers.find(Res) != ExpandedIntegers.end()) Mapped |= 16; if (ExpandedFloats.find(Res) != ExpandedFloats.end()) Mapped |= 32; if (SplitVectors.find(Res) != SplitVectors.end()) Mapped |= 64; if (WidenedVectors.find(Res) != WidenedVectors.end()) Mapped |= 128; if (PromotedFloats.find(Res) != PromotedFloats.end()) Mapped |= 256; if (Node.getNodeId() != Processed) { // Since we allow ReplacedValues to map deleted nodes, it may map nodes // marked NewNode too, since a deleted node may have been reallocated as // another node that has not been seen by the LegalizeTypes machinery. if ((Node.getNodeId() == NewNode && Mapped > 1) || (Node.getNodeId() != NewNode && Mapped != 0)) { dbgs() << "Unprocessed value in a map!"; Failed = true; } } else if (isTypeLegal(VT) || IgnoreNodeResults(&Node)) { if (Mapped > 1) { dbgs() << "Value with legal type was transformed!"; Failed = true; } } else { // If the value can be kept in HW registers, softening machinery can // leave it unchanged and don't put it to any map. if (Mapped == 0 && !(getTypeAction(VT) == TargetLowering::TypeSoftenFloat && isLegalInHWReg(VT))) { dbgs() << "Processed value not in any map!"; Failed = true; } else if (Mapped & (Mapped - 1)) { dbgs() << "Value in multiple maps!"; Failed = true; } } if (Failed) { if (Mapped & 1) dbgs() << " ReplacedValues"; if (Mapped & 2) dbgs() << " PromotedIntegers"; if (Mapped & 4) dbgs() << " SoftenedFloats"; if (Mapped & 8) dbgs() << " ScalarizedVectors"; if (Mapped & 16) dbgs() << " ExpandedIntegers"; if (Mapped & 32) dbgs() << " ExpandedFloats"; if (Mapped & 64) dbgs() << " SplitVectors"; if (Mapped & 128) dbgs() << " WidenedVectors"; if (Mapped & 256) dbgs() << " PromotedFloats"; dbgs() << "\n"; llvm_unreachable(nullptr); } } } // Checked that NewNodes are only used by other NewNodes. for (unsigned i = 0, e = NewNodes.size(); i != e; ++i) { SDNode *N = NewNodes[i]; for (SDNode::use_iterator UI = N->use_begin(), UE = N->use_end(); UI != UE; ++UI) assert(UI->getNodeId() == NewNode && "NewNode used by non-NewNode!"); } }
/// LowerCCCCallTo - functions arguments are copied from virtual regs to /// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted. /// TODO: sret. SDValue MSP430TargetLowering::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, DebugLoc 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, getTargetMachine(), ArgLocs, *DAG.getContext()); CCInfo.AnalyzeCallOperands(Outs, CC_MSP430); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); Chain = DAG.getCALLSEQ_START(Chain ,DAG.getConstant(NumBytes, getPointerTy(), true)); 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, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[i]; // Promote the value if needed. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); 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; } // 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, MSP430::SPW, getPointerTy()); SDValue PtrOff = DAG.getNode(ISD::ADD, dl, getPointerTy(), StackPtr, DAG.getIntPtrConstant(VA.getLocMemOffset())); 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, &MemOpChains[0], MemOpChains.size()); // 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. SDValue InFlag; 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. if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i16); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i16); // 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 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(MSP430ISD::CALL, dl, NodeTys, &Ops[0], Ops.size()); InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. Chain = DAG.getCALLSEQ_END(Chain, DAG.getConstant(NumBytes, getPointerTy(), true), DAG.getConstant(0, getPointerTy(), true), InFlag); 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); }
SDValue NVPTXTargetLowering::LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); const DataLayout *TD = getDataLayout(); const Function *F = MF.getFunction(); const AttrListPtr &PAL = F->getAttributes(); SDValue Root = DAG.getRoot(); std::vector<SDValue> OutChains; bool isKernel = llvm::isKernelFunction(*F); bool isABI = (nvptxSubtarget.getSmVersion() >= 20); std::vector<Type *> argTypes; std::vector<const Argument *> theArgs; for (Function::const_arg_iterator I = F->arg_begin(), E = F->arg_end(); I != E; ++I) { theArgs.push_back(I); argTypes.push_back(I->getType()); } assert(argTypes.size() == Ins.size() && "Ins types and function types did not match"); int idx = 0; for (unsigned i=0, e=Ins.size(); i!=e; ++i, ++idx) { Type *Ty = argTypes[i]; EVT ObjectVT = getValueType(Ty); assert(ObjectVT == Ins[i].VT && "Ins type did not match function type"); // If the kernel argument is image*_t or sampler_t, convert it to // a i32 constant holding the parameter position. This can later // matched in the AsmPrinter to output the correct mangled name. if (isImageOrSamplerVal(theArgs[i], (theArgs[i]->getParent() ? theArgs[i]->getParent()->getParent() : 0))) { assert(isKernel && "Only kernels can have image/sampler params"); InVals.push_back(DAG.getConstant(i+1, MVT::i32)); continue; } if (theArgs[i]->use_empty()) { // argument is dead InVals.push_back(DAG.getNode(ISD::UNDEF, dl, ObjectVT)); continue; } // In the following cases, assign a node order of "idx+1" // to newly created nodes. The SDNOdes for params have to // appear in the same order as their order of appearance // in the original function. "idx+1" holds that order. if (PAL.getParamAttributes(i+1).hasAttribute(Attributes::ByVal) == false) { // A plain scalar. if (isABI || isKernel) { // If ABI, load from the param symbol SDValue Arg = getParamSymbol(DAG, idx); Value *srcValue = new Argument(PointerType::get(ObjectVT.getTypeForEVT( F->getContext()), llvm::ADDRESS_SPACE_PARAM)); SDValue p = DAG.getLoad(ObjectVT, dl, Root, Arg, MachinePointerInfo(srcValue), false, false, false, TD->getABITypeAlignment(ObjectVT.getTypeForEVT( F->getContext()))); if (p.getNode()) DAG.AssignOrdering(p.getNode(), idx+1); InVals.push_back(p); } else { // If no ABI, just move the param symbol SDValue Arg = getParamSymbol(DAG, idx, ObjectVT); SDValue p = DAG.getNode(NVPTXISD::MoveParam, dl, ObjectVT, Arg); if (p.getNode()) DAG.AssignOrdering(p.getNode(), idx+1); InVals.push_back(p); } continue; } // Param has ByVal attribute if (isABI || isKernel) { // Return MoveParam(param symbol). // Ideally, the param symbol can be returned directly, // but when SDNode builder decides to use it in a CopyToReg(), // machine instruction fails because TargetExternalSymbol // (not lowered) is target dependent, and CopyToReg assumes // the source is lowered. SDValue Arg = getParamSymbol(DAG, idx, getPointerTy()); SDValue p = DAG.getNode(NVPTXISD::MoveParam, dl, ObjectVT, Arg); if (p.getNode()) DAG.AssignOrdering(p.getNode(), idx+1); if (isKernel) InVals.push_back(p); else { SDValue p2 = DAG.getNode(ISD::INTRINSIC_WO_CHAIN, dl, ObjectVT, DAG.getConstant(Intrinsic::nvvm_ptr_local_to_gen, MVT::i32), p); InVals.push_back(p2); } } else { // Have to move a set of param symbols to registers and // store them locally and return the local pointer in InVals const PointerType *elemPtrType = dyn_cast<PointerType>(argTypes[i]); assert(elemPtrType && "Byval parameter should be a pointer type"); Type *elemType = elemPtrType->getElementType(); // Compute the constituent parts SmallVector<EVT, 16> vtparts; SmallVector<uint64_t, 16> offsets; ComputeValueVTs(*this, elemType, vtparts, &offsets, 0); unsigned totalsize = 0; for (unsigned j=0, je=vtparts.size(); j!=je; ++j) totalsize += vtparts[j].getStoreSizeInBits(); SDValue localcopy = DAG.getFrameIndex(MF.getFrameInfo()-> CreateStackObject(totalsize/8, 16, false), getPointerTy()); unsigned sizesofar = 0; std::vector<SDValue> theChains; for (unsigned j=0, je=vtparts.size(); j!=je; ++j) { unsigned numElems = 1; if (vtparts[j].isVector()) numElems = vtparts[j].getVectorNumElements(); for (unsigned k=0, ke=numElems; k!=ke; ++k) { EVT tmpvt = vtparts[j]; if (tmpvt.isVector()) tmpvt = tmpvt.getVectorElementType(); SDValue arg = DAG.getNode(NVPTXISD::MoveParam, dl, tmpvt, getParamSymbol(DAG, idx, tmpvt)); SDValue addr = DAG.getNode(ISD::ADD, dl, getPointerTy(), localcopy, DAG.getConstant(sizesofar, getPointerTy())); theChains.push_back(DAG.getStore(Chain, dl, arg, addr, MachinePointerInfo(), false, false, 0)); sizesofar += tmpvt.getStoreSizeInBits()/8; ++idx; } } --idx; Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &theChains[0], theChains.size()); InVals.push_back(localcopy); } } // Clang will check explicit VarArg and issue error if any. However, Clang // will let code with // implicit var arg like f() pass. // We treat this case as if the arg list is empty. //if (F.isVarArg()) { // assert(0 && "VarArg not supported yet!"); //} if (!OutChains.empty()) DAG.setRoot(DAG.getNode(ISD::TokenFactor, dl, MVT::Other, &OutChains[0], OutChains.size())); return Chain; }
SDValue NVPTXTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const { SelectionDAG &DAG = CLI.DAG; DebugLoc &dl = CLI.DL; SmallVector<ISD::OutputArg, 32> &Outs = CLI.Outs; SmallVector<SDValue, 32> &OutVals = CLI.OutVals; SmallVector<ISD::InputArg, 32> &Ins = CLI.Ins; SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; bool &isTailCall = CLI.IsTailCall; ArgListTy &Args = CLI.Args; Type *retTy = CLI.RetTy; ImmutableCallSite *CS = CLI.CS; bool isABI = (nvptxSubtarget.getSmVersion() >= 20); SDValue tempChain = Chain; Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(uniqueCallSite, true)); SDValue InFlag = Chain.getValue(1); assert((Outs.size() == Args.size()) && "Unexpected number of arguments to function call"); unsigned paramCount = 0; // Declare the .params or .reg need to pass values // to the function for (unsigned i=0, e=Outs.size(); i!=e; ++i) { EVT VT = Outs[i].VT; if (Outs[i].Flags.isByVal() == false) { // Plain scalar // for ABI, declare .param .b<size> .param<n>; // for nonABI, declare .reg .b<size> .param<n>; unsigned isReg = 1; if (isABI) isReg = 0; unsigned sz = VT.getSizeInBits(); if (VT.isInteger() && (sz < 32)) sz = 32; SDVTList DeclareParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue DeclareParamOps[] = { Chain, DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(sz, MVT::i32), DAG.getConstant(isReg, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareScalarParam, dl, DeclareParamVTs, DeclareParamOps, 5); InFlag = Chain.getValue(1); SDVTList CopyParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CopyParamOps[] = { Chain, DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(0, MVT::i32), OutVals[i], InFlag }; unsigned opcode = NVPTXISD::StoreParam; if (isReg) opcode = NVPTXISD::MoveToParam; else { if (Outs[i].Flags.isZExt()) opcode = NVPTXISD::StoreParamU32; else if (Outs[i].Flags.isSExt()) opcode = NVPTXISD::StoreParamS32; } Chain = DAG.getNode(opcode, dl, CopyParamVTs, CopyParamOps, 5); InFlag = Chain.getValue(1); ++paramCount; continue; } // struct or vector SmallVector<EVT, 16> vtparts; const PointerType *PTy = dyn_cast<PointerType>(Args[i].Ty); assert(PTy && "Type of a byval parameter should be pointer"); ComputeValueVTs(*this, PTy->getElementType(), vtparts); if (isABI) { // declare .param .align 16 .b8 .param<n>[<size>]; unsigned sz = Outs[i].Flags.getByValSize(); SDVTList DeclareParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); // The ByValAlign in the Outs[i].Flags is alway set at this point, so we // don't need to // worry about natural alignment or not. See TargetLowering::LowerCallTo() SDValue DeclareParamOps[] = { Chain, DAG.getConstant(Outs[i].Flags.getByValAlign(), MVT::i32), DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(sz, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareParam, dl, DeclareParamVTs, DeclareParamOps, 5); InFlag = Chain.getValue(1); unsigned curOffset = 0; for (unsigned j=0,je=vtparts.size(); j!=je; ++j) { unsigned elems = 1; EVT elemtype = vtparts[j]; if (vtparts[j].isVector()) { elems = vtparts[j].getVectorNumElements(); elemtype = vtparts[j].getVectorElementType(); } for (unsigned k=0,ke=elems; k!=ke; ++k) { unsigned sz = elemtype.getSizeInBits(); if (elemtype.isInteger() && (sz < 8)) sz = 8; SDValue srcAddr = DAG.getNode(ISD::ADD, dl, getPointerTy(), OutVals[i], DAG.getConstant(curOffset, getPointerTy())); SDValue theVal = DAG.getLoad(elemtype, dl, tempChain, srcAddr, MachinePointerInfo(), false, false, false, 0); SDVTList CopyParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CopyParamOps[] = { Chain, DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(curOffset, MVT::i32), theVal, InFlag }; Chain = DAG.getNode(NVPTXISD::StoreParam, dl, CopyParamVTs, CopyParamOps, 5); InFlag = Chain.getValue(1); curOffset += sz/8; } } ++paramCount; continue; } // Non-abi, struct or vector // Declare a bunch or .reg .b<size> .param<n> unsigned curOffset = 0; for (unsigned j=0,je=vtparts.size(); j!=je; ++j) { unsigned elems = 1; EVT elemtype = vtparts[j]; if (vtparts[j].isVector()) { elems = vtparts[j].getVectorNumElements(); elemtype = vtparts[j].getVectorElementType(); } for (unsigned k=0,ke=elems; k!=ke; ++k) { unsigned sz = elemtype.getSizeInBits(); if (elemtype.isInteger() && (sz < 32)) sz = 32; SDVTList DeclareParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue DeclareParamOps[] = { Chain, DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(sz, MVT::i32), DAG.getConstant(1, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareScalarParam, dl, DeclareParamVTs, DeclareParamOps, 5); InFlag = Chain.getValue(1); SDValue srcAddr = DAG.getNode(ISD::ADD, dl, getPointerTy(), OutVals[i], DAG.getConstant(curOffset, getPointerTy())); SDValue theVal = DAG.getLoad(elemtype, dl, tempChain, srcAddr, MachinePointerInfo(), false, false, false, 0); SDVTList CopyParamVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CopyParamOps[] = { Chain, DAG.getConstant(paramCount, MVT::i32), DAG.getConstant(0, MVT::i32), theVal, InFlag }; Chain = DAG.getNode(NVPTXISD::MoveToParam, dl, CopyParamVTs, CopyParamOps, 5); InFlag = Chain.getValue(1); ++paramCount; } } } GlobalAddressSDNode *Func = dyn_cast<GlobalAddressSDNode>(Callee.getNode()); unsigned retAlignment = 0; // Handle Result unsigned retCount = 0; if (Ins.size() > 0) { SmallVector<EVT, 16> resvtparts; ComputeValueVTs(*this, retTy, resvtparts); // Declare one .param .align 16 .b8 func_retval0[<size>] for ABI or // individual .reg .b<size> func_retval<0..> for non ABI unsigned resultsz = 0; for (unsigned i=0,e=resvtparts.size(); i!=e; ++i) { unsigned elems = 1; EVT elemtype = resvtparts[i]; if (resvtparts[i].isVector()) { elems = resvtparts[i].getVectorNumElements(); elemtype = resvtparts[i].getVectorElementType(); } for (unsigned j=0,je=elems; j!=je; ++j) { unsigned sz = elemtype.getSizeInBits(); if (isABI == false) { if (elemtype.isInteger() && (sz < 32)) sz = 32; } else { if (elemtype.isInteger() && (sz < 8)) sz = 8; } if (isABI == false) { SDVTList DeclareRetVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue DeclareRetOps[] = { Chain, DAG.getConstant(2, MVT::i32), DAG.getConstant(sz, MVT::i32), DAG.getConstant(retCount, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareRet, dl, DeclareRetVTs, DeclareRetOps, 5); InFlag = Chain.getValue(1); ++retCount; } resultsz += sz; } } if (isABI) { if (retTy->isPrimitiveType() || retTy->isIntegerTy() || retTy->isPointerTy() ) { // Scalar needs to be at least 32bit wide if (resultsz < 32) resultsz = 32; SDVTList DeclareRetVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue DeclareRetOps[] = { Chain, DAG.getConstant(1, MVT::i32), DAG.getConstant(resultsz, MVT::i32), DAG.getConstant(0, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareRet, dl, DeclareRetVTs, DeclareRetOps, 5); InFlag = Chain.getValue(1); } else { if (Func) { // direct call if (!llvm::getAlign(*(CS->getCalledFunction()), 0, retAlignment)) retAlignment = getDataLayout()->getABITypeAlignment(retTy); } else { // indirect call const CallInst *CallI = dyn_cast<CallInst>(CS->getInstruction()); if (!llvm::getAlign(*CallI, 0, retAlignment)) retAlignment = getDataLayout()->getABITypeAlignment(retTy); } SDVTList DeclareRetVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue DeclareRetOps[] = { Chain, DAG.getConstant(retAlignment, MVT::i32), DAG.getConstant(resultsz/8, MVT::i32), DAG.getConstant(0, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::DeclareRetParam, dl, DeclareRetVTs, DeclareRetOps, 5); InFlag = Chain.getValue(1); } } } if (!Func) { // This is indirect function call case : PTX requires a prototype of the // form // proto_0 : .callprototype(.param .b32 _) _ (.param .b32 _); // to be emitted, and the label has to used as the last arg of call // instruction. // The prototype is embedded in a string and put as the operand for an // INLINEASM SDNode. SDVTList InlineAsmVTs = DAG.getVTList(MVT::Other, MVT::Glue); std::string proto_string = getPrototype(retTy, Args, Outs, retAlignment); const char *asmstr = nvTM->getManagedStrPool()-> getManagedString(proto_string.c_str())->c_str(); SDValue InlineAsmOps[] = { Chain, DAG.getTargetExternalSymbol(asmstr, getPointerTy()), DAG.getMDNode(0), DAG.getTargetConstant(0, MVT::i32), InFlag }; Chain = DAG.getNode(ISD::INLINEASM, dl, InlineAsmVTs, InlineAsmOps, 5); InFlag = Chain.getValue(1); } // Op to just print "call" SDVTList PrintCallVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue PrintCallOps[] = { Chain, DAG.getConstant(isABI ? ((Ins.size()==0) ? 0 : 1) : retCount, MVT::i32), InFlag }; Chain = DAG.getNode(Func?(NVPTXISD::PrintCallUni):(NVPTXISD::PrintCall), dl, PrintCallVTs, PrintCallOps, 3); InFlag = Chain.getValue(1); // Ops to print out the function name SDVTList CallVoidVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CallVoidOps[] = { Chain, Callee, InFlag }; Chain = DAG.getNode(NVPTXISD::CallVoid, dl, CallVoidVTs, CallVoidOps, 3); InFlag = Chain.getValue(1); // Ops to print out the param list SDVTList CallArgBeginVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CallArgBeginOps[] = { Chain, InFlag }; Chain = DAG.getNode(NVPTXISD::CallArgBegin, dl, CallArgBeginVTs, CallArgBeginOps, 2); InFlag = Chain.getValue(1); for (unsigned i=0, e=paramCount; i!=e; ++i) { unsigned opcode; if (i==(e-1)) opcode = NVPTXISD::LastCallArg; else opcode = NVPTXISD::CallArg; SDVTList CallArgVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CallArgOps[] = { Chain, DAG.getConstant(1, MVT::i32), DAG.getConstant(i, MVT::i32), InFlag }; Chain = DAG.getNode(opcode, dl, CallArgVTs, CallArgOps, 4); InFlag = Chain.getValue(1); } SDVTList CallArgEndVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue CallArgEndOps[] = { Chain, DAG.getConstant(Func ? 1 : 0, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::CallArgEnd, dl, CallArgEndVTs, CallArgEndOps, 3); InFlag = Chain.getValue(1); if (!Func) { SDVTList PrototypeVTs = DAG.getVTList(MVT::Other, MVT::Glue); SDValue PrototypeOps[] = { Chain, DAG.getConstant(uniqueCallSite, MVT::i32), InFlag }; Chain = DAG.getNode(NVPTXISD::Prototype, dl, PrototypeVTs, PrototypeOps, 3); InFlag = Chain.getValue(1); } // Generate loads from param memory/moves from registers for result if (Ins.size() > 0) { if (isABI) { unsigned resoffset = 0; for (unsigned i=0,e=Ins.size(); i!=e; ++i) { unsigned sz = Ins[i].VT.getSizeInBits(); if (Ins[i].VT.isInteger() && (sz < 8)) sz = 8; std::vector<EVT> LoadRetVTs; LoadRetVTs.push_back(Ins[i].VT); LoadRetVTs.push_back(MVT::Other); LoadRetVTs.push_back(MVT::Glue); std::vector<SDValue> LoadRetOps; LoadRetOps.push_back(Chain); LoadRetOps.push_back(DAG.getConstant(1, MVT::i32)); LoadRetOps.push_back(DAG.getConstant(resoffset, MVT::i32)); LoadRetOps.push_back(InFlag); SDValue retval = DAG.getNode(NVPTXISD::LoadParam, dl, LoadRetVTs, &LoadRetOps[0], LoadRetOps.size()); Chain = retval.getValue(1); InFlag = retval.getValue(2); InVals.push_back(retval); resoffset += sz/8; } } else { SmallVector<EVT, 16> resvtparts; ComputeValueVTs(*this, retTy, resvtparts); assert(Ins.size() == resvtparts.size() && "Unexpected number of return values in non-ABI case"); unsigned paramNum = 0; for (unsigned i=0,e=Ins.size(); i!=e; ++i) { assert(EVT(Ins[i].VT) == resvtparts[i] && "Unexpected EVT type in non-ABI case"); unsigned numelems = 1; EVT elemtype = Ins[i].VT; if (Ins[i].VT.isVector()) { numelems = Ins[i].VT.getVectorNumElements(); elemtype = Ins[i].VT.getVectorElementType(); } std::vector<SDValue> tempRetVals; for (unsigned j=0; j<numelems; ++j) { std::vector<EVT> MoveRetVTs; MoveRetVTs.push_back(elemtype); MoveRetVTs.push_back(MVT::Other); MoveRetVTs.push_back(MVT::Glue); std::vector<SDValue> MoveRetOps; MoveRetOps.push_back(Chain); MoveRetOps.push_back(DAG.getConstant(0, MVT::i32)); MoveRetOps.push_back(DAG.getConstant(paramNum, MVT::i32)); MoveRetOps.push_back(InFlag); SDValue retval = DAG.getNode(NVPTXISD::LoadParam, dl, MoveRetVTs, &MoveRetOps[0], MoveRetOps.size()); Chain = retval.getValue(1); InFlag = retval.getValue(2); tempRetVals.push_back(retval); ++paramNum; } if (Ins[i].VT.isVector()) InVals.push_back(DAG.getNode(ISD::BUILD_VECTOR, dl, Ins[i].VT, &tempRetVals[0], tempRetVals.size())); else InVals.push_back(tempRetVals[0]); } } } Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(uniqueCallSite, true), DAG.getIntPtrConstant(uniqueCallSite+1, true), InFlag); uniqueCallSite++; // set isTailCall to false for now, until we figure out how to express // tail call optimization in PTX isTailCall = false; return Chain; }
std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) { unsigned Opcode = Node->getOpcode(); SDLoc DL(Node); /// // Instruction Selection not handled by the auto-generated // tablegen selection should be handled here. /// SDNode *Result; switch(Opcode) { default: break; case ISD::SUBE: { SDValue InFlag = Node->getOperand(2); Result = selectAddESubE(Mips::SUBu, InFlag, InFlag.getOperand(0), DL, Node); return std::make_pair(true, Result); } case ISD::ADDE: { if (Subtarget.hasDSP()) // Select DSP instructions, ADDSC and ADDWC. break; SDValue InFlag = Node->getOperand(2); Result = selectAddESubE(Mips::ADDu, InFlag, InFlag.getValue(0), DL, Node); return std::make_pair(true, Result); } case ISD::ConstantFP: { ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(Node); if (Node->getValueType(0) == MVT::f64 && CN->isExactlyValue(+0.0)) { if (Subtarget.hasMips64()) { SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, Mips::ZERO_64, MVT::i64); Result = CurDAG->getMachineNode(Mips::DMTC1, DL, MVT::f64, Zero); } else { SDValue Zero = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), DL, Mips::ZERO, MVT::i32); Result = CurDAG->getMachineNode(Mips::BuildPairF64, DL, MVT::f64, Zero, Zero); } return std::make_pair(true, Result); } break; } case ISD::Constant: { const ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node); unsigned Size = CN->getValueSizeInBits(0); if (Size == 32) break; MipsAnalyzeImmediate AnalyzeImm; int64_t Imm = CN->getSExtValue(); const MipsAnalyzeImmediate::InstSeq &Seq = AnalyzeImm.Analyze(Imm, Size, false); MipsAnalyzeImmediate::InstSeq::const_iterator Inst = Seq.begin(); SDLoc DL(CN); SDNode *RegOpnd; SDValue ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), MVT::i64); // The first instruction can be a LUi which is different from other // instructions (ADDiu, ORI and SLL) in that it does not have a register // operand. if (Inst->Opc == Mips::LUi64) RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, ImmOpnd); else RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, CurDAG->getRegister(Mips::ZERO_64, MVT::i64), ImmOpnd); // The remaining instructions in the sequence are handled here. for (++Inst; Inst != Seq.end(); ++Inst) { ImmOpnd = CurDAG->getTargetConstant(SignExtend64<16>(Inst->ImmOpnd), MVT::i64); RegOpnd = CurDAG->getMachineNode(Inst->Opc, DL, MVT::i64, SDValue(RegOpnd, 0), ImmOpnd); } return std::make_pair(true, RegOpnd); } case ISD::INTRINSIC_W_CHAIN: { switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { default: break; case Intrinsic::mips_cfcmsa: { SDValue ChainIn = Node->getOperand(0); SDValue RegIdx = Node->getOperand(2); SDValue Reg = CurDAG->getCopyFromReg(ChainIn, DL, getMSACtrlReg(RegIdx), MVT::i32); return std::make_pair(true, Reg.getNode()); } } break; } case ISD::INTRINSIC_WO_CHAIN: { switch (cast<ConstantSDNode>(Node->getOperand(0))->getZExtValue()) { default: break; case Intrinsic::mips_move_v: // Like an assignment but will always produce a move.v even if // unnecessary. return std::make_pair(true, CurDAG->getMachineNode(Mips::MOVE_V, DL, Node->getValueType(0), Node->getOperand(1))); } break; } case ISD::INTRINSIC_VOID: { switch (cast<ConstantSDNode>(Node->getOperand(1))->getZExtValue()) { default: break; case Intrinsic::mips_ctcmsa: { SDValue ChainIn = Node->getOperand(0); SDValue RegIdx = Node->getOperand(2); SDValue Value = Node->getOperand(3); SDValue ChainOut = CurDAG->getCopyToReg(ChainIn, DL, getMSACtrlReg(RegIdx), Value); return std::make_pair(true, ChainOut.getNode()); } } break; } case MipsISD::ThreadPointer: { EVT PtrVT = getTargetLowering()->getPointerTy(); unsigned RdhwrOpc, DestReg; if (PtrVT == MVT::i32) { RdhwrOpc = Mips::RDHWR; DestReg = Mips::V1; } else { RdhwrOpc = Mips::RDHWR64; DestReg = Mips::V1_64; } SDNode *Rdhwr = CurDAG->getMachineNode(RdhwrOpc, SDLoc(Node), Node->getValueType(0), CurDAG->getRegister(Mips::HWR29, MVT::i32)); SDValue Chain = CurDAG->getCopyToReg(CurDAG->getEntryNode(), DL, DestReg, SDValue(Rdhwr, 0)); SDValue ResNode = CurDAG->getCopyFromReg(Chain, DL, DestReg, PtrVT); ReplaceUses(SDValue(Node, 0), ResNode); return std::make_pair(true, ResNode.getNode()); } case ISD::BUILD_VECTOR: { // Select appropriate ldi.[bhwd] instructions for constant splats of // 128-bit when MSA is enabled. Fixup any register class mismatches that // occur as a result. // // This allows the compiler to use a wider range of immediates than would // otherwise be allowed. If, for example, v4i32 could only use ldi.h then // it would not be possible to load { 0x01010101, 0x01010101, 0x01010101, // 0x01010101 } without using a constant pool. This would be sub-optimal // when // 'ldi.b wd, 1' is capable of producing that bit-pattern in the // same set/ of registers. Similarly, ldi.h isn't capable of producing { // 0x00000000, 0x00000001, 0x00000000, 0x00000001 } but 'ldi.d wd, 1' can. BuildVectorSDNode *BVN = cast<BuildVectorSDNode>(Node); APInt SplatValue, SplatUndef; unsigned SplatBitSize; bool HasAnyUndefs; unsigned LdiOp; EVT ResVecTy = BVN->getValueType(0); EVT ViaVecTy; if (!Subtarget.hasMSA() || !BVN->getValueType(0).is128BitVector()) return std::make_pair(false, (SDNode*)NULL); if (!BVN->isConstantSplat(SplatValue, SplatUndef, SplatBitSize, HasAnyUndefs, 8, !Subtarget.isLittle())) return std::make_pair(false, (SDNode*)NULL); switch (SplatBitSize) { default: return std::make_pair(false, (SDNode*)NULL); case 8: LdiOp = Mips::LDI_B; ViaVecTy = MVT::v16i8; break; case 16: LdiOp = Mips::LDI_H; ViaVecTy = MVT::v8i16; break; case 32: LdiOp = Mips::LDI_W; ViaVecTy = MVT::v4i32; break; case 64: LdiOp = Mips::LDI_D; ViaVecTy = MVT::v2i64; break; } if (!SplatValue.isSignedIntN(10)) return std::make_pair(false, (SDNode*)NULL); SDValue Imm = CurDAG->getTargetConstant(SplatValue, ViaVecTy.getVectorElementType()); SDNode *Res = CurDAG->getMachineNode(LdiOp, SDLoc(Node), ViaVecTy, Imm); if (ResVecTy != ViaVecTy) { // If LdiOp is writing to a different register class to ResVecTy, then // fix it up here. This COPY_TO_REGCLASS should never cause a move.v // since the source and destination register sets contain the same // registers. const TargetLowering *TLI = getTargetLowering(); MVT ResVecTySimple = ResVecTy.getSimpleVT(); const TargetRegisterClass *RC = TLI->getRegClassFor(ResVecTySimple); Res = CurDAG->getMachineNode(Mips::COPY_TO_REGCLASS, SDLoc(Node), ResVecTy, SDValue(Res, 0), CurDAG->getTargetConstant(RC->getID(), MVT::i32)); } return std::make_pair(true, Res); } } return std::make_pair(false, (SDNode*)NULL); }
SDValue BPFTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const { SelectionDAG &DAG = CLI.DAG; auto &Outs = CLI.Outs; auto &OutVals = CLI.OutVals; auto &Ins = CLI.Ins; SDValue Chain = CLI.Chain; SDValue Callee = CLI.Callee; bool &IsTailCall = CLI.IsTailCall; CallingConv::ID CallConv = CLI.CallConv; bool IsVarArg = CLI.IsVarArg; MachineFunction &MF = DAG.getMachineFunction(); // BPF target does not support tail call optimization. IsTailCall = false; switch (CallConv) { default: report_fatal_error("Unsupported calling convention"); case CallingConv::Fast: case CallingConv::C: break; } // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, IsVarArg, MF, ArgLocs, *DAG.getContext()); CCInfo.AnalyzeCallOperands(Outs, CC_BPF64); unsigned NumBytes = CCInfo.getNextStackOffset(); if (Outs.size() >= 6) { DiagnosticInfoUnsupported Err(CLI.DL, *MF.getFunction(), "too many args to ", Callee); DAG.getContext()->diagnose(Err); } for (auto &Arg : Outs) { ISD::ArgFlagsTy Flags = Arg.Flags; if (!Flags.isByVal()) continue; DiagnosticInfoUnsupported Err(CLI.DL, *MF.getFunction(), "pass by value not supported ", Callee); DAG.getContext()->diagnose(Err); } Chain = DAG.getCALLSEQ_START( Chain, DAG.getConstant(NumBytes, getPointerTy(), true), CLI.DL); SmallVector<std::pair<unsigned, SDValue>, 5> RegsToPass; // Walk arg assignments for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[i]; // Promote the value if needed. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info"); case CCValAssign::Full: break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, CLI.DL, VA.getLocVT(), Arg); break; case CCValAssign::ZExt: Arg = DAG.getNode(ISD::ZERO_EXTEND, CLI.DL, VA.getLocVT(), Arg); break; case CCValAssign::AExt: Arg = DAG.getNode(ISD::ANY_EXTEND, CLI.DL, VA.getLocVT(), Arg); break; } // Push arguments into RegsToPass vector if (VA.isRegLoc()) RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg)); else llvm_unreachable("call arg pass bug"); } 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 (auto &Reg : RegsToPass) { Chain = DAG.getCopyToReg(Chain, CLI.DL, Reg.first, Reg.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. if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), CLI.DL, getPointerTy(), G->getOffset(), 0); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), 0); // 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 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 (InFlag.getNode()) Ops.push_back(InFlag); Chain = DAG.getNode(BPFISD::CALL, CLI.DL, NodeTys, Ops); InFlag = Chain.getValue(1); // Create the CALLSEQ_END node. Chain = DAG.getCALLSEQ_END( Chain, DAG.getConstant(NumBytes, getPointerTy(), true), DAG.getConstant(0, getPointerTy(), true), InFlag, CLI.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, CLI.DL, DAG, InVals); }
static bool isIntS32Immediate(SDValue Op, int32_t &Imm) { return isIntS32Immediate(Op.getNode(), Imm); }
SDValue BlackfinTargetLowering::LowerCall(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, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { // Blackfin target does not yet support tail call optimization. isTailCall = false; // Analyze operands of the call, assigning locations to each operand. SmallVector<CCValAssign, 16> ArgLocs; CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), DAG.getTarget(), ArgLocs, *DAG.getContext()); CCInfo.AllocateStack(12, 4); // ABI requires 12 bytes stack space CCInfo.AnalyzeCallOperands(Outs, CC_Blackfin); // Get the size of the outgoing arguments stack space requirement. unsigned ArgsSize = CCInfo.getNextStackOffset(); Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, true)); SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass; SmallVector<SDValue, 8> MemOpChains; // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { CCValAssign &VA = ArgLocs[i]; SDValue Arg = OutVals[i]; // Promote the value if needed. switch (VA.getLocInfo()) { default: llvm_unreachable("Unknown loc info!"); 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; } // 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() && "CCValAssign must be RegLoc or MemLoc"); int Offset = VA.getLocMemOffset(); assert(Offset%4 == 0 && "Unaligned LocMemOffset"); assert(VA.getLocVT()==MVT::i32 && "Illegal CCValAssign type"); SDValue SPN = DAG.getCopyFromReg(Chain, dl, BF::SP, MVT::i32); SDValue OffsetN = DAG.getIntPtrConstant(Offset); OffsetN = DAG.getNode(ISD::ADD, dl, MVT::i32, SPN, OffsetN); MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, OffsetN, 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, &MemOpChains[0], MemOpChains.size()); // 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. SDValue InFlag; 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. if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32); std::vector<EVT> NodeTys; NodeTys.push_back(MVT::Other); // Returns a chain NodeTys.push_back(MVT::Glue); // Returns a flag for retval copy to use. SDValue Ops[] = { Chain, Callee, InFlag }; Chain = DAG.getNode(BFISD::CALL, dl, NodeTys, Ops, InFlag.getNode() ? 3 : 2); InFlag = Chain.getValue(1); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, true), DAG.getIntPtrConstant(0, true), InFlag); InFlag = Chain.getValue(1); // Assign locations to each value returned by this call. SmallVector<CCValAssign, 16> RVLocs; CCState RVInfo(CallConv, isVarArg, DAG.getMachineFunction(), DAG.getTarget(), RVLocs, *DAG.getContext()); RVInfo.AnalyzeCallResult(Ins, RetCC_Blackfin); // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { CCValAssign &RV = RVLocs[i]; unsigned Reg = RV.getLocReg(); Chain = DAG.getCopyFromReg(Chain, dl, Reg, RVLocs[i].getLocVT(), InFlag); SDValue Val = Chain.getValue(0); InFlag = Chain.getValue(2); Chain = Chain.getValue(1); // Callee is responsible for extending any i16 return values. switch (RV.getLocInfo()) { case CCValAssign::SExt: Val = DAG.getNode(ISD::AssertSext, dl, RV.getLocVT(), Val, DAG.getValueType(RV.getValVT())); break; case CCValAssign::ZExt: Val = DAG.getNode(ISD::AssertZext, dl, RV.getLocVT(), Val, DAG.getValueType(RV.getValVT())); break; default: break; } // Truncate to valtype if (RV.getLocInfo() != CCValAssign::Full) Val = DAG.getNode(ISD::TRUNCATE, dl, RV.getValVT(), Val); InVals.push_back(Val); } return Chain; }