|  | //===-- AlphaISelDAGToDAG.cpp - Alpha pattern matching inst selector ------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file defines a pattern matching instruction selector for Alpha, | 
|  | // converting from a legalized dag to a Alpha dag. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "Alpha.h" | 
|  | #include "AlphaTargetMachine.h" | 
|  | #include "AlphaISelLowering.h" | 
|  | #include "llvm/CodeGen/MachineInstrBuilder.h" | 
|  | #include "llvm/CodeGen/MachineFrameInfo.h" | 
|  | #include "llvm/CodeGen/MachineFunction.h" | 
|  | #include "llvm/CodeGen/MachineRegisterInfo.h" | 
|  | #include "llvm/CodeGen/SelectionDAG.h" | 
|  | #include "llvm/CodeGen/SelectionDAGISel.h" | 
|  | #include "llvm/Target/TargetOptions.h" | 
|  | #include "llvm/Constants.h" | 
|  | #include "llvm/DerivedTypes.h" | 
|  | #include "llvm/GlobalValue.h" | 
|  | #include "llvm/Intrinsics.h" | 
|  | #include "llvm/Support/Compiler.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/MathExtras.h" | 
|  | #include <algorithm> | 
|  | #include <queue> | 
|  | #include <set> | 
|  | using namespace llvm; | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | //===--------------------------------------------------------------------===// | 
|  | /// AlphaDAGToDAGISel - Alpha specific code to select Alpha machine | 
|  | /// instructions for SelectionDAG operations. | 
|  | class AlphaDAGToDAGISel : public SelectionDAGISel { | 
|  | AlphaTargetLowering AlphaLowering; | 
|  |  | 
|  | static const int64_t IMM_LOW  = -32768; | 
|  | static const int64_t IMM_HIGH = 32767; | 
|  | static const int64_t IMM_MULT = 65536; | 
|  | static const int64_t IMM_FULLHIGH = IMM_HIGH + IMM_HIGH * IMM_MULT; | 
|  | static const int64_t IMM_FULLLOW = IMM_LOW + IMM_LOW  * IMM_MULT; | 
|  |  | 
|  | static int64_t get_ldah16(int64_t x) { | 
|  | int64_t y = x / IMM_MULT; | 
|  | if (x % IMM_MULT > IMM_HIGH) | 
|  | ++y; | 
|  | return y; | 
|  | } | 
|  |  | 
|  | static int64_t get_lda16(int64_t x) { | 
|  | return x - get_ldah16(x) * IMM_MULT; | 
|  | } | 
|  |  | 
|  | /// get_zapImm - Return a zap mask if X is a valid immediate for a zapnot | 
|  | /// instruction (if not, return 0).  Note that this code accepts partial | 
|  | /// zap masks.  For example (and LHS, 1) is a valid zap, as long we know | 
|  | /// that the bits 1-7 of LHS are already zero.  If LHS is non-null, we are | 
|  | /// in checking mode.  If LHS is null, we assume that the mask has already | 
|  | /// been validated before. | 
|  | uint64_t get_zapImm(SDOperand LHS, uint64_t Constant) { | 
|  | uint64_t BitsToCheck = 0; | 
|  | unsigned Result = 0; | 
|  | for (unsigned i = 0; i != 8; ++i) { | 
|  | if (((Constant >> 8*i) & 0xFF) == 0) { | 
|  | // nothing to do. | 
|  | } else { | 
|  | Result |= 1 << i; | 
|  | if (((Constant >> 8*i) & 0xFF) == 0xFF) { | 
|  | // If the entire byte is set, zapnot the byte. | 
|  | } else if (LHS.Val == 0) { | 
|  | // Otherwise, if the mask was previously validated, we know its okay | 
|  | // to zapnot this entire byte even though all the bits aren't set. | 
|  | } else { | 
|  | // Otherwise we don't know that the it's okay to zapnot this entire | 
|  | // byte.  Only do this iff we can prove that the missing bits are | 
|  | // already null, so the bytezap doesn't need to really null them. | 
|  | BitsToCheck |= ~Constant & (0xFF << 8*i); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // If there are missing bits in a byte (for example, X & 0xEF00), check to | 
|  | // see if the missing bits (0x1000) are already known zero if not, the zap | 
|  | // isn't okay to do, as it won't clear all the required bits. | 
|  | if (BitsToCheck && | 
|  | !CurDAG->MaskedValueIsZero(LHS, | 
|  | APInt(LHS.getValueSizeInBits(), | 
|  | BitsToCheck))) | 
|  | return 0; | 
|  |  | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | static uint64_t get_zapImm(uint64_t x) { | 
|  | unsigned build = 0; | 
|  | for(int i = 0; i != 8; ++i) { | 
|  | if ((x & 0x00FF) == 0x00FF) | 
|  | build |= 1 << i; | 
|  | else if ((x & 0x00FF) != 0) | 
|  | return 0; | 
|  | x >>= 8; | 
|  | } | 
|  | return build; | 
|  | } | 
|  |  | 
|  |  | 
|  | static uint64_t getNearPower2(uint64_t x) { | 
|  | if (!x) return 0; | 
|  | unsigned at = CountLeadingZeros_64(x); | 
|  | uint64_t complow = 1 << (63 - at); | 
|  | uint64_t comphigh = 1 << (64 - at); | 
|  | //cerr << x << ":" << complow << ":" << comphigh << "\n"; | 
|  | if (abs(complow - x) <= abs(comphigh - x)) | 
|  | return complow; | 
|  | else | 
|  | return comphigh; | 
|  | } | 
|  |  | 
|  | static bool chkRemNearPower2(uint64_t x, uint64_t r, bool swap) { | 
|  | uint64_t y = getNearPower2(x); | 
|  | if (swap) | 
|  | return (y - x) == r; | 
|  | else | 
|  | return (x - y) == r; | 
|  | } | 
|  |  | 
|  | static bool isFPZ(SDOperand N) { | 
|  | ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); | 
|  | return (CN && (CN->getValueAPF().isZero())); | 
|  | } | 
|  | static bool isFPZn(SDOperand N) { | 
|  | ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); | 
|  | return (CN && CN->getValueAPF().isNegZero()); | 
|  | } | 
|  | static bool isFPZp(SDOperand N) { | 
|  | ConstantFPSDNode *CN = dyn_cast<ConstantFPSDNode>(N); | 
|  | return (CN && CN->getValueAPF().isPosZero()); | 
|  | } | 
|  |  | 
|  | public: | 
|  | AlphaDAGToDAGISel(TargetMachine &TM) | 
|  | : SelectionDAGISel(AlphaLowering), | 
|  | AlphaLowering(*(AlphaTargetLowering*)(TM.getTargetLowering())) | 
|  | {} | 
|  |  | 
|  | /// getI64Imm - Return a target constant with the specified value, of type | 
|  | /// i64. | 
|  | inline SDOperand getI64Imm(int64_t Imm) { | 
|  | return CurDAG->getTargetConstant(Imm, MVT::i64); | 
|  | } | 
|  |  | 
|  | // Select - Convert the specified operand from a target-independent to a | 
|  | // target-specific node if it hasn't already been changed. | 
|  | SDNode *Select(SDOperand Op); | 
|  |  | 
|  | /// InstructionSelectBasicBlock - This callback is invoked by | 
|  | /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. | 
|  | virtual void InstructionSelectBasicBlock(SelectionDAG &DAG); | 
|  |  | 
|  | virtual const char *getPassName() const { | 
|  | return "Alpha DAG->DAG Pattern Instruction Selection"; | 
|  | } | 
|  |  | 
|  | /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for | 
|  | /// inline asm expressions. | 
|  | virtual bool SelectInlineAsmMemoryOperand(const SDOperand &Op, | 
|  | char ConstraintCode, | 
|  | std::vector<SDOperand> &OutOps, | 
|  | SelectionDAG &DAG) { | 
|  | SDOperand Op0; | 
|  | switch (ConstraintCode) { | 
|  | default: return true; | 
|  | case 'm':   // memory | 
|  | Op0 = Op; | 
|  | AddToISelQueue(Op0); | 
|  | break; | 
|  | } | 
|  |  | 
|  | OutOps.push_back(Op0); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Include the pieces autogenerated from the target description. | 
|  | #include "AlphaGenDAGISel.inc" | 
|  |  | 
|  | private: | 
|  | SDOperand getGlobalBaseReg(); | 
|  | SDOperand getGlobalRetAddr(); | 
|  | void SelectCALL(SDOperand Op); | 
|  |  | 
|  | }; | 
|  | } | 
|  |  | 
|  | /// getGlobalBaseReg - Output the instructions required to put the | 
|  | /// GOT address into a register. | 
|  | /// | 
|  | SDOperand AlphaDAGToDAGISel::getGlobalBaseReg() { | 
|  | unsigned GP = 0; | 
|  | for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(), | 
|  | ee = RegInfo->livein_end(); ii != ee; ++ii) | 
|  | if (ii->first == Alpha::R29) { | 
|  | GP = ii->second; | 
|  | break; | 
|  | } | 
|  | assert(GP && "GOT PTR not in liveins"); | 
|  | return CurDAG->getCopyFromReg(CurDAG->getEntryNode(), | 
|  | GP, MVT::i64); | 
|  | } | 
|  |  | 
|  | /// getRASaveReg - Grab the return address | 
|  | /// | 
|  | SDOperand AlphaDAGToDAGISel::getGlobalRetAddr() { | 
|  | unsigned RA = 0; | 
|  | for(MachineRegisterInfo::livein_iterator ii = RegInfo->livein_begin(), | 
|  | ee = RegInfo->livein_end(); ii != ee; ++ii) | 
|  | if (ii->first == Alpha::R26) { | 
|  | RA = ii->second; | 
|  | break; | 
|  | } | 
|  | assert(RA && "RA PTR not in liveins"); | 
|  | return CurDAG->getCopyFromReg(CurDAG->getEntryNode(), | 
|  | RA, MVT::i64); | 
|  | } | 
|  |  | 
|  | /// InstructionSelectBasicBlock - This callback is invoked by | 
|  | /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. | 
|  | void AlphaDAGToDAGISel::InstructionSelectBasicBlock(SelectionDAG &DAG) { | 
|  | DEBUG(BB->dump()); | 
|  |  | 
|  | // Select target instructions for the DAG. | 
|  | DAG.setRoot(SelectRoot(DAG.getRoot())); | 
|  | DAG.RemoveDeadNodes(); | 
|  |  | 
|  | // Emit machine code to BB. | 
|  | ScheduleAndEmitDAG(DAG); | 
|  | } | 
|  |  | 
|  | // Select - Convert the specified operand from a target-independent to a | 
|  | // target-specific node if it hasn't already been changed. | 
|  | SDNode *AlphaDAGToDAGISel::Select(SDOperand Op) { | 
|  | SDNode *N = Op.Val; | 
|  | if (N->getOpcode() >= ISD::BUILTIN_OP_END && | 
|  | N->getOpcode() < AlphaISD::FIRST_NUMBER) { | 
|  | return NULL;   // Already selected. | 
|  | } | 
|  |  | 
|  | switch (N->getOpcode()) { | 
|  | default: break; | 
|  | case AlphaISD::CALL: | 
|  | SelectCALL(Op); | 
|  | return NULL; | 
|  |  | 
|  | case ISD::FrameIndex: { | 
|  | int FI = cast<FrameIndexSDNode>(N)->getIndex(); | 
|  | return CurDAG->SelectNodeTo(N, Alpha::LDA, MVT::i64, | 
|  | CurDAG->getTargetFrameIndex(FI, MVT::i32), | 
|  | getI64Imm(0)); | 
|  | } | 
|  | case ISD::GLOBAL_OFFSET_TABLE: { | 
|  | SDOperand Result = getGlobalBaseReg(); | 
|  | ReplaceUses(Op, Result); | 
|  | return NULL; | 
|  | } | 
|  | case AlphaISD::GlobalRetAddr: { | 
|  | SDOperand Result = getGlobalRetAddr(); | 
|  | ReplaceUses(Op, Result); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | case AlphaISD::DivCall: { | 
|  | SDOperand Chain = CurDAG->getEntryNode(); | 
|  | SDOperand N0 = Op.getOperand(0); | 
|  | SDOperand N1 = Op.getOperand(1); | 
|  | SDOperand N2 = Op.getOperand(2); | 
|  | AddToISelQueue(N0); | 
|  | AddToISelQueue(N1); | 
|  | AddToISelQueue(N2); | 
|  | Chain = CurDAG->getCopyToReg(Chain, Alpha::R24, N1, | 
|  | SDOperand(0,0)); | 
|  | Chain = CurDAG->getCopyToReg(Chain, Alpha::R25, N2, | 
|  | Chain.getValue(1)); | 
|  | Chain = CurDAG->getCopyToReg(Chain, Alpha::R27, N0, | 
|  | Chain.getValue(1)); | 
|  | SDNode *CNode = | 
|  | CurDAG->getTargetNode(Alpha::JSRs, MVT::Other, MVT::Flag, | 
|  | Chain, Chain.getValue(1)); | 
|  | Chain = CurDAG->getCopyFromReg(Chain, Alpha::R27, MVT::i64, | 
|  | SDOperand(CNode, 1)); | 
|  | return CurDAG->SelectNodeTo(N, Alpha::BISr, MVT::i64, Chain, Chain); | 
|  | } | 
|  |  | 
|  | case ISD::READCYCLECOUNTER: { | 
|  | SDOperand Chain = N->getOperand(0); | 
|  | AddToISelQueue(Chain); //Select chain | 
|  | return CurDAG->getTargetNode(Alpha::RPCC, MVT::i64, MVT::Other, | 
|  | Chain); | 
|  | } | 
|  |  | 
|  | case ISD::Constant: { | 
|  | uint64_t uval = cast<ConstantSDNode>(N)->getValue(); | 
|  |  | 
|  | if (uval == 0) { | 
|  | SDOperand Result = CurDAG->getCopyFromReg(CurDAG->getEntryNode(), | 
|  | Alpha::R31, MVT::i64); | 
|  | ReplaceUses(Op, Result); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | int64_t val = (int64_t)uval; | 
|  | int32_t val32 = (int32_t)val; | 
|  | if (val <= IMM_HIGH + IMM_HIGH * IMM_MULT && | 
|  | val >= IMM_LOW  + IMM_LOW  * IMM_MULT) | 
|  | break; //(LDAH (LDA)) | 
|  | if ((uval >> 32) == 0 && //empty upper bits | 
|  | val32 <= IMM_HIGH + IMM_HIGH * IMM_MULT) | 
|  | // val32 >= IMM_LOW  + IMM_LOW  * IMM_MULT) //always true | 
|  | break; //(zext (LDAH (LDA))) | 
|  | //Else use the constant pool | 
|  | ConstantInt *C = ConstantInt::get(Type::Int64Ty, uval); | 
|  | SDOperand CPI = CurDAG->getTargetConstantPool(C, MVT::i64); | 
|  | SDNode *Tmp = CurDAG->getTargetNode(Alpha::LDAHr, MVT::i64, CPI, | 
|  | getGlobalBaseReg()); | 
|  | return CurDAG->SelectNodeTo(N, Alpha::LDQr, MVT::i64, MVT::Other, | 
|  | CPI, SDOperand(Tmp, 0), CurDAG->getEntryNode()); | 
|  | } | 
|  | case ISD::TargetConstantFP: { | 
|  | ConstantFPSDNode *CN = cast<ConstantFPSDNode>(N); | 
|  | bool isDouble = N->getValueType(0) == MVT::f64; | 
|  | MVT::ValueType T = isDouble ? MVT::f64 : MVT::f32; | 
|  | if (CN->getValueAPF().isPosZero()) { | 
|  | return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYST : Alpha::CPYSS, | 
|  | T, CurDAG->getRegister(Alpha::F31, T), | 
|  | CurDAG->getRegister(Alpha::F31, T)); | 
|  | } else if (CN->getValueAPF().isNegZero()) { | 
|  | return CurDAG->SelectNodeTo(N, isDouble ? Alpha::CPYSNT : Alpha::CPYSNS, | 
|  | T, CurDAG->getRegister(Alpha::F31, T), | 
|  | CurDAG->getRegister(Alpha::F31, T)); | 
|  | } else { | 
|  | abort(); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | case ISD::SETCC: | 
|  | if (MVT::isFloatingPoint(N->getOperand(0).Val->getValueType(0))) { | 
|  | ISD::CondCode CC = cast<CondCodeSDNode>(N->getOperand(2))->get(); | 
|  |  | 
|  | unsigned Opc = Alpha::WTF; | 
|  | bool rev = false; | 
|  | bool inv = false; | 
|  | switch(CC) { | 
|  | default: DEBUG(N->dump(CurDAG)); assert(0 && "Unknown FP comparison!"); | 
|  | case ISD::SETEQ: case ISD::SETOEQ: case ISD::SETUEQ: | 
|  | Opc = Alpha::CMPTEQ; break; | 
|  | case ISD::SETLT: case ISD::SETOLT: case ISD::SETULT: | 
|  | Opc = Alpha::CMPTLT; break; | 
|  | case ISD::SETLE: case ISD::SETOLE: case ISD::SETULE: | 
|  | Opc = Alpha::CMPTLE; break; | 
|  | case ISD::SETGT: case ISD::SETOGT: case ISD::SETUGT: | 
|  | Opc = Alpha::CMPTLT; rev = true; break; | 
|  | case ISD::SETGE: case ISD::SETOGE: case ISD::SETUGE: | 
|  | Opc = Alpha::CMPTLE; rev = true; break; | 
|  | case ISD::SETNE: case ISD::SETONE: case ISD::SETUNE: | 
|  | Opc = Alpha::CMPTEQ; inv = true; break; | 
|  | case ISD::SETO: | 
|  | Opc = Alpha::CMPTUN; inv = true; break; | 
|  | case ISD::SETUO: | 
|  | Opc = Alpha::CMPTUN; break; | 
|  | }; | 
|  | SDOperand tmp1 = N->getOperand(rev?1:0); | 
|  | SDOperand tmp2 = N->getOperand(rev?0:1); | 
|  | AddToISelQueue(tmp1); | 
|  | AddToISelQueue(tmp2); | 
|  | SDNode *cmp = CurDAG->getTargetNode(Opc, MVT::f64, tmp1, tmp2); | 
|  | if (inv) | 
|  | cmp = CurDAG->getTargetNode(Alpha::CMPTEQ, MVT::f64, SDOperand(cmp, 0), | 
|  | CurDAG->getRegister(Alpha::F31, MVT::f64)); | 
|  | switch(CC) { | 
|  | case ISD::SETUEQ: case ISD::SETULT: case ISD::SETULE: | 
|  | case ISD::SETUNE: case ISD::SETUGT: case ISD::SETUGE: | 
|  | { | 
|  | SDNode* cmp2 = CurDAG->getTargetNode(Alpha::CMPTUN, MVT::f64, | 
|  | tmp1, tmp2); | 
|  | cmp = CurDAG->getTargetNode(Alpha::ADDT, MVT::f64, | 
|  | SDOperand(cmp2, 0), SDOperand(cmp, 0)); | 
|  | break; | 
|  | } | 
|  | default: break; | 
|  | } | 
|  |  | 
|  | SDNode* LD = CurDAG->getTargetNode(Alpha::FTOIT, MVT::i64, SDOperand(cmp, 0)); | 
|  | return CurDAG->getTargetNode(Alpha::CMPULT, MVT::i64, | 
|  | CurDAG->getRegister(Alpha::R31, MVT::i64), | 
|  | SDOperand(LD,0)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ISD::SELECT: | 
|  | if (MVT::isFloatingPoint(N->getValueType(0)) && | 
|  | (N->getOperand(0).getOpcode() != ISD::SETCC || | 
|  | !MVT::isFloatingPoint(N->getOperand(0).getOperand(1).getValueType()))) { | 
|  | //This should be the condition not covered by the Patterns | 
|  | //FIXME: Don't have SelectCode die, but rather return something testable | 
|  | // so that things like this can be caught in fall though code | 
|  | //move int to fp | 
|  | bool isDouble = N->getValueType(0) == MVT::f64; | 
|  | SDOperand cond = N->getOperand(0); | 
|  | SDOperand TV = N->getOperand(1); | 
|  | SDOperand FV = N->getOperand(2); | 
|  | AddToISelQueue(cond); | 
|  | AddToISelQueue(TV); | 
|  | AddToISelQueue(FV); | 
|  |  | 
|  | SDNode* LD = CurDAG->getTargetNode(Alpha::ITOFT, MVT::f64, cond); | 
|  | return CurDAG->getTargetNode(isDouble?Alpha::FCMOVNET:Alpha::FCMOVNES, | 
|  | MVT::f64, FV, TV, SDOperand(LD,0)); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case ISD::AND: { | 
|  | ConstantSDNode* SC = NULL; | 
|  | ConstantSDNode* MC = NULL; | 
|  | if (N->getOperand(0).getOpcode() == ISD::SRL && | 
|  | (MC = dyn_cast<ConstantSDNode>(N->getOperand(1))) && | 
|  | (SC = dyn_cast<ConstantSDNode>(N->getOperand(0).getOperand(1)))) { | 
|  | uint64_t sval = SC->getValue(); | 
|  | uint64_t mval = MC->getValue(); | 
|  | // If the result is a zap, let the autogened stuff handle it. | 
|  | if (get_zapImm(N->getOperand(0), mval)) | 
|  | break; | 
|  | // given mask X, and shift S, we want to see if there is any zap in the | 
|  | // mask if we play around with the botton S bits | 
|  | uint64_t dontcare = (~0ULL) >> (64 - sval); | 
|  | uint64_t mask = mval << sval; | 
|  |  | 
|  | if (get_zapImm(mask | dontcare)) | 
|  | mask = mask | dontcare; | 
|  |  | 
|  | if (get_zapImm(mask)) { | 
|  | AddToISelQueue(N->getOperand(0).getOperand(0)); | 
|  | SDOperand Z = | 
|  | SDOperand(CurDAG->getTargetNode(Alpha::ZAPNOTi, MVT::i64, | 
|  | N->getOperand(0).getOperand(0), | 
|  | getI64Imm(get_zapImm(mask))), 0); | 
|  | return CurDAG->getTargetNode(Alpha::SRLr, MVT::i64, Z, | 
|  | getI64Imm(sval)); | 
|  | } | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | return SelectCode(Op); | 
|  | } | 
|  |  | 
|  | void AlphaDAGToDAGISel::SelectCALL(SDOperand Op) { | 
|  | //TODO: add flag stuff to prevent nondeturministic breakage! | 
|  |  | 
|  | SDNode *N = Op.Val; | 
|  | SDOperand Chain = N->getOperand(0); | 
|  | SDOperand Addr = N->getOperand(1); | 
|  | SDOperand InFlag(0,0);  // Null incoming flag value. | 
|  | AddToISelQueue(Chain); | 
|  |  | 
|  | std::vector<SDOperand> CallOperands; | 
|  | std::vector<MVT::ValueType> TypeOperands; | 
|  |  | 
|  | //grab the arguments | 
|  | for(int i = 2, e = N->getNumOperands(); i < e; ++i) { | 
|  | TypeOperands.push_back(N->getOperand(i).getValueType()); | 
|  | AddToISelQueue(N->getOperand(i)); | 
|  | CallOperands.push_back(N->getOperand(i)); | 
|  | } | 
|  | int count = N->getNumOperands() - 2; | 
|  |  | 
|  | static const unsigned args_int[] = {Alpha::R16, Alpha::R17, Alpha::R18, | 
|  | Alpha::R19, Alpha::R20, Alpha::R21}; | 
|  | static const unsigned args_float[] = {Alpha::F16, Alpha::F17, Alpha::F18, | 
|  | Alpha::F19, Alpha::F20, Alpha::F21}; | 
|  |  | 
|  | for (int i = 6; i < count; ++i) { | 
|  | unsigned Opc = Alpha::WTF; | 
|  | if (MVT::isInteger(TypeOperands[i])) { | 
|  | Opc = Alpha::STQ; | 
|  | } else if (TypeOperands[i] == MVT::f32) { | 
|  | Opc = Alpha::STS; | 
|  | } else if (TypeOperands[i] == MVT::f64) { | 
|  | Opc = Alpha::STT; | 
|  | } else | 
|  | assert(0 && "Unknown operand"); | 
|  |  | 
|  | SDOperand Ops[] = { CallOperands[i],  getI64Imm((i - 6) * 8), | 
|  | CurDAG->getCopyFromReg(Chain, Alpha::R30, MVT::i64), | 
|  | Chain }; | 
|  | Chain = SDOperand(CurDAG->getTargetNode(Opc, MVT::Other, Ops, 4), 0); | 
|  | } | 
|  | for (int i = 0; i < std::min(6, count); ++i) { | 
|  | if (MVT::isInteger(TypeOperands[i])) { | 
|  | Chain = CurDAG->getCopyToReg(Chain, args_int[i], CallOperands[i], InFlag); | 
|  | InFlag = Chain.getValue(1); | 
|  | } else if (TypeOperands[i] == MVT::f32 || TypeOperands[i] == MVT::f64) { | 
|  | Chain = CurDAG->getCopyToReg(Chain, args_float[i], CallOperands[i], InFlag); | 
|  | InFlag = Chain.getValue(1); | 
|  | } else | 
|  | assert(0 && "Unknown operand"); | 
|  | } | 
|  |  | 
|  | // Finally, once everything is in registers to pass to the call, emit the | 
|  | // call itself. | 
|  | if (Addr.getOpcode() == AlphaISD::GPRelLo) { | 
|  | SDOperand GOT = getGlobalBaseReg(); | 
|  | Chain = CurDAG->getCopyToReg(Chain, Alpha::R29, GOT, InFlag); | 
|  | InFlag = Chain.getValue(1); | 
|  | Chain = SDOperand(CurDAG->getTargetNode(Alpha::BSR, MVT::Other, MVT::Flag, | 
|  | Addr.getOperand(0), Chain, InFlag), 0); | 
|  | } else { | 
|  | AddToISelQueue(Addr); | 
|  | Chain = CurDAG->getCopyToReg(Chain, Alpha::R27, Addr, InFlag); | 
|  | InFlag = Chain.getValue(1); | 
|  | Chain = SDOperand(CurDAG->getTargetNode(Alpha::JSR, MVT::Other, MVT::Flag, | 
|  | Chain, InFlag), 0); | 
|  | } | 
|  | InFlag = Chain.getValue(1); | 
|  |  | 
|  | std::vector<SDOperand> CallResults; | 
|  |  | 
|  | switch (N->getValueType(0)) { | 
|  | default: assert(0 && "Unexpected ret value!"); | 
|  | case MVT::Other: break; | 
|  | case MVT::i64: | 
|  | Chain = CurDAG->getCopyFromReg(Chain, Alpha::R0, MVT::i64, InFlag).getValue(1); | 
|  | CallResults.push_back(Chain.getValue(0)); | 
|  | break; | 
|  | case MVT::f32: | 
|  | Chain = CurDAG->getCopyFromReg(Chain, Alpha::F0, MVT::f32, InFlag).getValue(1); | 
|  | CallResults.push_back(Chain.getValue(0)); | 
|  | break; | 
|  | case MVT::f64: | 
|  | Chain = CurDAG->getCopyFromReg(Chain, Alpha::F0, MVT::f64, InFlag).getValue(1); | 
|  | CallResults.push_back(Chain.getValue(0)); | 
|  | break; | 
|  | } | 
|  |  | 
|  | CallResults.push_back(Chain); | 
|  | for (unsigned i = 0, e = CallResults.size(); i != e; ++i) | 
|  | ReplaceUses(Op.getValue(i), CallResults[i]); | 
|  | } | 
|  |  | 
|  |  | 
|  | /// createAlphaISelDag - This pass converts a legalized DAG into a | 
|  | /// Alpha-specific DAG, ready for instruction scheduling. | 
|  | /// | 
|  | FunctionPass *llvm::createAlphaISelDag(TargetMachine &TM) { | 
|  | return new AlphaDAGToDAGISel(TM); | 
|  | } |