SDValue DAGTypeLegalizer::ExpandOp_NormalStore(SDNode *N, unsigned OpNo) { assert(ISD::isNormalStore(N) && "This routine only for normal stores!"); assert(OpNo == 1 && "Can only expand the stored value so far"); DebugLoc dl = N->getDebugLoc(); StoreSDNode *St = cast<StoreSDNode>(N); EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), St->getValue().getValueType()); SDValue Chain = St->getChain(); SDValue Ptr = St->getBasePtr(); int SVOffset = St->getSrcValueOffset(); unsigned Alignment = St->getAlignment(); bool isVolatile = St->isVolatile(); assert(NVT.isByteSized() && "Expanded type not byte sized!"); unsigned IncrementSize = NVT.getSizeInBits() / 8; SDValue Lo, Hi; GetExpandedOp(St->getValue(), Lo, Hi); if (TLI.isBigEndian()) std::swap(Lo, Hi); Lo = DAG.getStore(Chain, dl, Lo, Ptr, St->getSrcValue(), SVOffset, isVolatile, Alignment); Ptr = DAG.getNode(ISD::ADD, dl, Ptr.getValueType(), Ptr, DAG.getIntPtrConstant(IncrementSize)); assert(isTypeLegal(Ptr.getValueType()) && "Pointers must be legal!"); Hi = DAG.getStore(Chain, dl, Hi, Ptr, St->getSrcValue(), SVOffset + IncrementSize, isVolatile, MinAlign(Alignment, IncrementSize)); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Lo, Hi); }
// Select - Convert the specified operand from a target-independent to a // target-specific node if it hasn't already been changed. SDNode *IA64DAGToDAGISel::Select(SDValue Op) { SDNode *N = Op.getNode(); if (N->isMachineOpcode()) return NULL; // Already selected. DebugLoc dl = Op.getDebugLoc(); switch (N->getOpcode()) { default: break; case IA64ISD::BRCALL: { // XXX: this is also a hack! SDValue Chain = N->getOperand(0); SDValue InFlag; // Null incoming flag value. if(N->getNumOperands()==3) { // we have an incoming chain, callee and flag InFlag = N->getOperand(2); } unsigned CallOpcode; SDValue CallOperand; // if we can call directly, do so if (GlobalAddressSDNode *GASD = dyn_cast<GlobalAddressSDNode>(N->getOperand(1))) { CallOpcode = IA64::BRCALL_IPREL_GA; CallOperand = CurDAG->getTargetGlobalAddress(GASD->getGlobal(), MVT::i64); } else if (isa<ExternalSymbolSDNode>(N->getOperand(1))) { // FIXME: we currently NEED this case for correctness, to avoid // "non-pic code with imm reloc.n against dynamic symbol" errors CallOpcode = IA64::BRCALL_IPREL_ES; CallOperand = N->getOperand(1); } else { // otherwise we need to load the function descriptor, // load the branch target (function)'s entry point and GP, // branch (call) then restore the GP SDValue FnDescriptor = N->getOperand(1); // load the branch target's entry point [mem] and // GP value [mem+8] SDValue targetEntryPoint= SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, FnDescriptor, CurDAG->getEntryNode()), 0); Chain = targetEntryPoint.getValue(1); SDValue targetGPAddr= SDValue(CurDAG->getTargetNode(IA64::ADDS, dl, MVT::i64, FnDescriptor, CurDAG->getConstant(8, MVT::i64)), 0); Chain = targetGPAddr.getValue(1); SDValue targetGP = SDValue(CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64,MVT::Other, targetGPAddr, CurDAG->getEntryNode()), 0); Chain = targetGP.getValue(1); Chain = CurDAG->getCopyToReg(Chain, dl, IA64::r1, targetGP, InFlag); InFlag = Chain.getValue(1); Chain = CurDAG->getCopyToReg(Chain, dl, IA64::B6, targetEntryPoint, InFlag); // FLAG these? InFlag = Chain.getValue(1); CallOperand = CurDAG->getRegister(IA64::B6, MVT::i64); CallOpcode = IA64::BRCALL_INDIRECT; } // Finally, once everything is setup, emit the call itself if (InFlag.getNode()) Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, MVT::Flag, CallOperand, InFlag), 0); else // there might be no arguments Chain = SDValue(CurDAG->getTargetNode(CallOpcode, dl, MVT::Other, MVT::Flag, CallOperand, Chain), 0); InFlag = Chain.getValue(1); std::vector<SDValue> CallResults; CallResults.push_back(Chain); CallResults.push_back(InFlag); for (unsigned i = 0, e = CallResults.size(); i != e; ++i) ReplaceUses(Op.getValue(i), CallResults[i]); return NULL; } case IA64ISD::GETFD: { SDValue Input = N->getOperand(0); return CurDAG->getTargetNode(IA64::GETFD, dl, MVT::i64, Input); } case ISD::FDIV: case ISD::SDIV: case ISD::UDIV: case ISD::SREM: case ISD::UREM: return SelectDIV(Op); case ISD::TargetConstantFP: { SDValue Chain = CurDAG->getEntryNode(); // this is a constant, so.. SDValue V; ConstantFPSDNode* N2 = cast<ConstantFPSDNode>(N); if (N2->getValueAPF().isPosZero()) { V = CurDAG->getCopyFromReg(Chain, dl, IA64::F0, MVT::f64); } else if (N2->isExactlyValue(N2->getValueType(0) == MVT::f32 ? APFloat(+1.0f) : APFloat(+1.0))) { V = CurDAG->getCopyFromReg(Chain, dl, IA64::F1, MVT::f64); } else assert(0 && "Unexpected FP constant!"); ReplaceUses(SDValue(N, 0), V); return 0; } case ISD::FrameIndex: { // TODO: reduce creepyness int FI = cast<FrameIndexSDNode>(N)->getIndex(); if (N->hasOneUse()) return CurDAG->SelectNodeTo(N, IA64::MOV, MVT::i64, CurDAG->getTargetFrameIndex(FI, MVT::i64)); else return CurDAG->getTargetNode(IA64::MOV, dl, MVT::i64, CurDAG->getTargetFrameIndex(FI, MVT::i64)); } case ISD::ConstantPool: { // TODO: nuke the constant pool // (ia64 doesn't need one) ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(N); Constant *C = CP->getConstVal(); SDValue CPI = CurDAG->getTargetConstantPool(C, MVT::i64, CP->getAlignment()); return CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, // ? CurDAG->getRegister(IA64::r1, MVT::i64), CPI); } case ISD::GlobalAddress: { GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal(); SDValue GA = CurDAG->getTargetGlobalAddress(GV, MVT::i64); SDValue Tmp = SDValue(CurDAG->getTargetNode(IA64::ADDL_GA, dl, MVT::i64, CurDAG->getRegister(IA64::r1, MVT::i64), GA), 0); return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, MVT::Other, Tmp, CurDAG->getEntryNode()); } /* XXX case ISD::ExternalSymbol: { SDValue EA = CurDAG->getTargetExternalSymbol( cast<ExternalSymbolSDNode>(N)->getSymbol(), MVT::i64); SDValue Tmp = CurDAG->getTargetNode(IA64::ADDL_EA, dl, MVT::i64, CurDAG->getRegister(IA64::r1, MVT::i64), EA); return CurDAG->getTargetNode(IA64::LD8, dl, MVT::i64, Tmp); } */ case ISD::LOAD: { // FIXME: load -1, not 1, for bools? LoadSDNode *LD = cast<LoadSDNode>(N); SDValue Chain = LD->getChain(); SDValue Address = LD->getBasePtr(); MVT TypeBeingLoaded = LD->getMemoryVT(); unsigned Opc; switch (TypeBeingLoaded.getSimpleVT()) { default: #ifndef NDEBUG N->dump(CurDAG); #endif assert(0 && "Cannot load this type!"); case MVT::i1: { // this is a bool Opc = IA64::LD1; // first we load a byte, then compare for != 0 if(N->getValueType(0) == MVT::i1) { // XXX: early exit! return CurDAG->SelectNodeTo(N, IA64::CMPNE, MVT::i1, MVT::Other, SDValue(CurDAG->getTargetNode(Opc, dl, MVT::i64, Address), 0), CurDAG->getRegister(IA64::r0, MVT::i64), Chain); } /* otherwise, we want to load a bool into something bigger: LD1 will do that for us, so we just fall through */ } case MVT::i8: Opc = IA64::LD1; break; case MVT::i16: Opc = IA64::LD2; break; case MVT::i32: Opc = IA64::LD4; break; case MVT::i64: Opc = IA64::LD8; break; case MVT::f32: Opc = IA64::LDF4; break; case MVT::f64: Opc = IA64::LDF8; break; } // TODO: comment this return CurDAG->SelectNodeTo(N, Opc, N->getValueType(0), MVT::Other, Address, Chain); } case ISD::STORE: { StoreSDNode *ST = cast<StoreSDNode>(N); SDValue Address = ST->getBasePtr(); SDValue Chain = ST->getChain(); unsigned Opc; if (ISD::isNON_TRUNCStore(N)) { switch (N->getOperand(1).getValueType().getSimpleVT()) { default: assert(0 && "unknown type in store"); case MVT::i1: { // this is a bool Opc = IA64::ST1; // we store either 0 or 1 as a byte // first load zero! SDValue Initial = CurDAG->getCopyFromReg(Chain, dl, IA64::r0, MVT::i64); Chain = Initial.getValue(1); // then load 1 into the same reg iff the predicate to store is 1 SDValue Tmp = ST->getValue(); Tmp = SDValue(CurDAG->getTargetNode(IA64::TPCADDS, dl, MVT::i64, Initial, CurDAG->getTargetConstant(1, MVT::i64), Tmp), 0); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, Address, Tmp, Chain); } case MVT::i64: Opc = IA64::ST8; break; case MVT::f64: Opc = IA64::STF8; break; } } else { // Truncating store switch(ST->getMemoryVT().getSimpleVT()) { default: assert(0 && "unknown type in truncstore"); case MVT::i8: Opc = IA64::ST1; break; case MVT::i16: Opc = IA64::ST2; break; case MVT::i32: Opc = IA64::ST4; break; case MVT::f32: Opc = IA64::STF4; break; } } SDValue N1 = N->getOperand(1); SDValue N2 = N->getOperand(2); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, N2, N1, Chain); } case ISD::BRCOND: { SDValue Chain = N->getOperand(0); SDValue CC = N->getOperand(1); MachineBasicBlock *Dest = cast<BasicBlockSDNode>(N->getOperand(2))->getBasicBlock(); //FIXME - we do NOT need long branches all the time return CurDAG->SelectNodeTo(N, IA64::BRLCOND_NOTCALL, MVT::Other, CC, CurDAG->getBasicBlock(Dest), Chain); } case ISD::CALLSEQ_START: case ISD::CALLSEQ_END: { int64_t Amt = cast<ConstantSDNode>(N->getOperand(1))->getZExtValue(); unsigned Opc = N->getOpcode() == ISD::CALLSEQ_START ? IA64::ADJUSTCALLSTACKDOWN : IA64::ADJUSTCALLSTACKUP; SDValue N0 = N->getOperand(0); return CurDAG->SelectNodeTo(N, Opc, MVT::Other, getI64Imm(Amt), N0); } case ISD::BR: // FIXME: we don't need long branches all the time! SDValue N0 = N->getOperand(0); return CurDAG->SelectNodeTo(N, IA64::BRL_NOTCALL, MVT::Other, N->getOperand(1), N0); } return SelectCode(Op); }