SDValue LanaiTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); const Constant *C = N->getConstVal(); const LanaiTargetObjectFile *TLOF = static_cast<const LanaiTargetObjectFile *>( getTargetMachine().getObjFileLowering()); // If the code model is small or constant will be placed in the small section, // then assume address will fit in 21-bits. if (getTargetMachine().getCodeModel() == CodeModel::Small || TLOF->isConstantInSmallSection(DAG.getDataLayout(), C)) { SDValue Small = DAG.getTargetConstantPool( C, MVT::i32, N->getAlignment(), N->getOffset(), LanaiII::MO_NO_FLAG); return DAG.getNode(ISD::OR, DL, MVT::i32, DAG.getRegister(Lanai::R0, MVT::i32), DAG.getNode(LanaiISD::SMALL, DL, MVT::i32, Small)); } else { uint8_t OpFlagHi = LanaiII::MO_ABS_HI; uint8_t OpFlagLo = LanaiII::MO_ABS_LO; SDValue Hi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), N->getOffset(), OpFlagHi); SDValue Lo = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), N->getOffset(), OpFlagLo); Hi = DAG.getNode(LanaiISD::HI, DL, MVT::i32, Hi); Lo = DAG.getNode(LanaiISD::LO, DL, MVT::i32, Lo); SDValue Result = DAG.getNode(ISD::OR, DL, MVT::i32, Hi, Lo); return Result; } }
SDValue MipsTargetLowering:: LowerConstantPool(SDValue Op, SelectionDAG &DAG) { SDValue ResNode; ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); Constant *C = N->getConstVal(); SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment()); // FIXME there isn't actually debug info here DebugLoc dl = Op.getDebugLoc(); // gp_rel relocation // FIXME: we should reference the constant pool using small data sections, // but the asm printer currently doens't support this feature without // hacking it. This feature should come soon so we can uncomment the // stuff below. //if (IsInSmallSection(C->getType())) { // SDValue GPRelNode = DAG.getNode(MipsISD::GPRel, MVT::i32, CP); // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); //} else { // %hi/%lo relocation SDValue HiPart = DAG.getNode(MipsISD::Hi, dl, MVT::i32, CP); SDValue Lo = DAG.getNode(MipsISD::Lo, dl, MVT::i32, CP); ResNode = DAG.getNode(ISD::ADD, dl, MVT::i32, HiPart, Lo); //} return ResNode; }
static SDValue LowerCONSTANTPOOL(SDValue Op, SelectionDAG &DAG) { ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); // FIXME there isn't really any debug info here DebugLoc dl = Op.getDebugLoc(); Constant *C = N->getConstVal(); SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment()); SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, CP); SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, CP); return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi); }
// FIXME: PIC here // FIXME: This is just dirty hack. We need to lower cpool properly SDValue SystemZTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) { DebugLoc dl = Op.getDebugLoc(); ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); SDValue Result = DAG.getTargetConstantPool(CP->getConstVal(), getPointerTy(), CP->getAlignment(), CP->getOffset()); return DAG.getNode(SystemZISD::PCRelativeWrapper, dl, getPointerTy(), Result); }
SDValue MBlazeTargetLowering:: LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { SDValue ResNode; ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); const Constant *C = N->getConstVal(); DebugLoc dl = Op.getDebugLoc(); SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), N->getOffset(), 0); return DAG.getNode(MBlazeISD::Wrap, dl, MVT::i32, CP); }
SDValue SparcTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); // FIXME there isn't really any debug info here DebugLoc dl = Op.getDebugLoc(); const Constant *C = N->getConstVal(); SDValue CP = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment()); SDValue Hi = DAG.getNode(SPISD::Hi, dl, MVT::i32, CP); SDValue Lo = DAG.getNode(SPISD::Lo, dl, MVT::i32, CP); if (getTargetMachine().getRelocationModel() != Reloc::PIC_) return DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi); SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, dl, getPointerTy()); SDValue RelAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Lo, Hi); SDValue AbsAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, GlobalBase, RelAddr); return DAG.getLoad(getPointerTy(), dl, DAG.getEntryNode(), AbsAddr, NULL, 0, false, false, 0); }
SDValue VectorProcTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { DebugLoc dl = Op.getDebugLoc(); EVT PtrVT = Op.getValueType(); ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); SDValue Res; if (CP->isMachineConstantPoolEntry()) { Res = DAG.getTargetConstantPool(CP->getMachineCPVal(), PtrVT, CP->getAlignment()); } else { Res = DAG.getTargetConstantPool(CP->getConstVal(), PtrVT, CP->getAlignment()); } return Res; }
SDValue Cpu0TargetLowering:: LowerConstantPool(SDValue Op, SelectionDAG &DAG) const { SDValue ResNode; ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op); const Constant *C = N->getConstVal(); // FIXME there isn't actually debug info here DebugLoc dl = Op.getDebugLoc(); // gp_rel relocation // FIXME: we should reference the constant pool using small data sections, // but the asm printer currently doesn't support this feature without // hacking it. This feature should come soon so we can uncomment the // stuff below. //if (IsInSmallSection(C->getType())) { // SDValue GPRelNode = DAG.getNode(Cpu0ISD::GPRel, MVT::i32, CP); // SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(MVT::i32); // ResNode = DAG.getNode(ISD::ADD, MVT::i32, GOT, GPRelNode); if (getTargetMachine().getRelocationModel() != Reloc::PIC_) { SDValue CPHi = DAG.getTargetConstantPool(C, MVT::i32, N->getAlignment(), N->getOffset(), Cpu0II::MO_ABS); SDValue ResNode = DAG.getNode(Cpu0ISD::Hi, dl, MVT::i32, CPHi); } else { EVT ValTy = Op.getValueType(); unsigned GOTFlag = Cpu0II::MO_GOT; unsigned OFSTFlag = Cpu0II::MO_ABS; SDValue CP = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), N->getOffset(), GOTFlag); CP = DAG.getNode(Cpu0ISD::Wrapper, dl, ValTy, GetGlobalReg(DAG, ValTy), CP); SDValue Load = DAG.getLoad(ValTy, dl, DAG.getEntryNode(), CP, MachinePointerInfo::getConstantPool(), false, false, false, 0); SDValue CPLo = DAG.getTargetConstantPool(C, ValTy, N->getAlignment(), N->getOffset(), OFSTFlag); SDValue Lo = DAG.getNode(Cpu0ISD::Lo, dl, ValTy, CPLo); ResNode = DAG.getNode(ISD::ADD, dl, ValTy, Load, Lo); } return ResNode; }
/// 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(); }
// 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); }
/// 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(); }