| //===-- PPC32ISelPattern.cpp - A pattern matching inst selector for PPC32 -===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file was developed by Nate Begeman and is distributed under |
| // the University of Illinois Open Source License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines a pattern matching instruction selector for 32 bit PowerPC. |
| // Magic number generation for integer divide from the PowerPC Compiler Writer's |
| // Guide, section 3.2.3.5 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "PPC.h" |
| #include "PPCInstrBuilder.h" |
| #include "PPCTargetMachine.h" |
| #include "PPCISelLowering.h" |
| #include "llvm/Constants.h" |
| #include "llvm/Function.h" |
| #include "llvm/CodeGen/MachineConstantPool.h" |
| #include "llvm/CodeGen/MachineFunction.h" |
| #include "llvm/CodeGen/SelectionDAG.h" |
| #include "llvm/CodeGen/SelectionDAGISel.h" |
| #include "llvm/CodeGen/SSARegMap.h" |
| #include "llvm/Target/TargetData.h" |
| #include "llvm/Target/TargetOptions.h" |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/MathExtras.h" |
| #include "llvm/ADT/Statistic.h" |
| #include <set> |
| #include <algorithm> |
| using namespace llvm; |
| |
| namespace { |
| Statistic<> Recorded("ppc-codegen", "Number of recording ops emitted"); |
| Statistic<> FusedFP ("ppc-codegen", "Number of fused fp operations"); |
| Statistic<> FrameOff("ppc-codegen", "Number of frame idx offsets collapsed"); |
| |
| //===--------------------------------------------------------------------===// |
| // ISel - PPC32 specific code to select PPC32 machine instructions for |
| // SelectionDAG operations. |
| //===--------------------------------------------------------------------===// |
| |
| class ISel : public SelectionDAGISel { |
| PPCTargetLowering PPCLowering; |
| SelectionDAG *ISelDAG; // Hack to support us having a dag->dag transform |
| // for sdiv and udiv until it is put into the future |
| // dag combiner. |
| |
| /// ExprMap - As shared expressions are codegen'd, we keep track of which |
| /// vreg the value is produced in, so we only emit one copy of each compiled |
| /// tree. |
| std::map<SDOperand, unsigned> ExprMap; |
| |
| unsigned GlobalBaseReg; |
| bool GlobalBaseInitialized; |
| bool RecordSuccess; |
| public: |
| ISel(TargetMachine &TM) : SelectionDAGISel(PPCLowering), PPCLowering(TM), |
| ISelDAG(0) {} |
| |
| /// runOnFunction - Override this function in order to reset our per-function |
| /// variables. |
| virtual bool runOnFunction(Function &Fn) { |
| // Make sure we re-emit a set of the global base reg if necessary |
| GlobalBaseInitialized = false; |
| return SelectionDAGISel::runOnFunction(Fn); |
| } |
| |
| /// InstructionSelectBasicBlock - This callback is invoked by |
| /// SelectionDAGISel when it has created a SelectionDAG for us to codegen. |
| virtual void InstructionSelectBasicBlock(SelectionDAG &DAG) { |
| DEBUG(BB->dump()); |
| // Codegen the basic block. |
| ISelDAG = &DAG; |
| Select(DAG.getRoot()); |
| |
| // Clear state used for selection. |
| ExprMap.clear(); |
| ISelDAG = 0; |
| } |
| |
| // convenience functions for virtual register creation |
| inline unsigned MakeIntReg() { |
| return RegMap->createVirtualRegister(PPC::GPRCRegisterClass); |
| } |
| |
| // dag -> dag expanders for integer divide by constant |
| SDOperand BuildSDIVSequence(SDOperand N); |
| SDOperand BuildUDIVSequence(SDOperand N); |
| |
| unsigned getGlobalBaseReg(); |
| void MoveCRtoGPR(unsigned CCReg, ISD::CondCode CC, unsigned Result); |
| bool SelectBitfieldInsert(SDOperand OR, unsigned Result); |
| unsigned FoldIfWideZeroExtend(SDOperand N); |
| unsigned SelectCC(SDOperand LHS, SDOperand RHS, ISD::CondCode CC); |
| bool SelectIntImmediateExpr(SDOperand N, unsigned Result, |
| unsigned OCHi, unsigned OCLo, |
| bool IsArithmetic = false, bool Negate = false); |
| unsigned SelectExpr(SDOperand N, bool Recording=false); |
| void Select(SDOperand N); |
| |
| unsigned SelectAddr(SDOperand N, unsigned& Reg, int& offset); |
| void SelectBranchCC(SDOperand N); |
| |
| virtual const char *getPassName() const { |
| return "PowerPC Pattern Instruction Selection"; |
| } |
| }; |
| |
| // isRunOfOnes - Returns true iff Val consists of one contiguous run of 1s with |
| // any number of 0s on either side. The 1s are allowed to wrap from LSB to |
| // MSB, so 0x000FFF0, 0x0000FFFF, and 0xFF0000FF are all runs. 0x0F0F0000 is |
| // not, since all 1s are not contiguous. |
| static bool isRunOfOnes(unsigned Val, unsigned &MB, unsigned &ME) { |
| if (isShiftedMask_32(Val)) { |
| // look for the first non-zero bit |
| MB = CountLeadingZeros_32(Val); |
| // look for the first zero bit after the run of ones |
| ME = CountLeadingZeros_32((Val - 1) ^ Val); |
| return true; |
| } else if (isShiftedMask_32(Val = ~Val)) { // invert mask |
| // effectively look for the first zero bit |
| ME = CountLeadingZeros_32(Val) - 1; |
| // effectively look for the first one bit after the run of zeros |
| MB = CountLeadingZeros_32((Val - 1) ^ Val) + 1; |
| return true; |
| } |
| // no run present |
| return false; |
| } |
| |
| // isRotateAndMask - Returns true if Mask and Shift can be folded in to a rotate |
| // and mask opcode and mask operation. |
| static bool isRotateAndMask(unsigned Opcode, unsigned Shift, unsigned Mask, |
| bool IsShiftMask, |
| unsigned &SH, unsigned &MB, unsigned &ME) { |
| if (Shift > 31) return false; |
| unsigned Indeterminant = ~0; // bit mask marking indeterminant results |
| |
| if (Opcode == ISD::SHL) { // shift left |
| // apply shift to mask if it comes first |
| if (IsShiftMask) Mask = Mask << Shift; |
| // determine which bits are made indeterminant by shift |
| Indeterminant = ~(0xFFFFFFFFu << Shift); |
| } else if (Opcode == ISD::SRL) { // shift rights |
| // apply shift to mask if it comes first |
| if (IsShiftMask) Mask = Mask >> Shift; |
| // determine which bits are made indeterminant by shift |
| Indeterminant = ~(0xFFFFFFFFu >> Shift); |
| // adjust for the left rotate |
| Shift = 32 - Shift; |
| } |
| |
| // if the mask doesn't intersect any Indeterminant bits |
| if (Mask && !(Mask & Indeterminant)) { |
| SH = Shift; |
| // make sure the mask is still a mask (wrap arounds may not be) |
| return isRunOfOnes(Mask, MB, ME); |
| } |
| |
| // can't do it |
| return false; |
| } |
| |
| // isIntImmediate - This method tests to see if a constant operand. |
| // If so Imm will receive the 32 bit value. |
| static bool isIntImmediate(SDOperand N, unsigned& Imm) { |
| // test for constant |
| if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N)) { |
| // retrieve value |
| Imm = (unsigned)CN->getValue(); |
| // passes muster |
| return true; |
| } |
| // not a constant |
| return false; |
| } |
| |
| // isOpcWithIntImmediate - This method tests to see if the node is a specific |
| // opcode and that it has a immediate integer right operand. |
| // If so Imm will receive the 32 bit value. |
| static bool isOpcWithIntImmediate(SDOperand N, unsigned Opc, unsigned& Imm) { |
| return N.getOpcode() == Opc && isIntImmediate(N.getOperand(1), Imm); |
| } |
| |
| // isOprShiftImm - Returns true if the specified operand is a shift opcode with |
| // a immediate shift count less than 32. |
| static bool isOprShiftImm(SDOperand N, unsigned& Opc, unsigned& SH) { |
| Opc = N.getOpcode(); |
| return (Opc == ISD::SHL || Opc == ISD::SRL || Opc == ISD::SRA) && |
| isIntImmediate(N.getOperand(1), SH) && SH < 32; |
| } |
| |
| // isOprNot - Returns true if the specified operand is an xor with immediate -1. |
| static bool isOprNot(SDOperand N) { |
| unsigned Imm; |
| return isOpcWithIntImmediate(N, ISD::XOR, Imm) && (signed)Imm == -1; |
| } |
| |
| // Immediate constant composers. |
| // Lo16 - grabs the lo 16 bits from a 32 bit constant. |
| // Hi16 - grabs the hi 16 bits from a 32 bit constant. |
| // HA16 - computes the hi bits required if the lo bits are add/subtracted in |
| // arithmethically. |
| static unsigned Lo16(unsigned x) { return x & 0x0000FFFF; } |
| static unsigned Hi16(unsigned x) { return Lo16(x >> 16); } |
| static unsigned HA16(unsigned x) { return Hi16((signed)x - (signed short)x); } |
| |
| /// NodeHasRecordingVariant - If SelectExpr can always produce code for |
| /// NodeOpcode that also sets CR0 as a side effect, return true. Otherwise, |
| /// return false. |
| static bool NodeHasRecordingVariant(unsigned NodeOpcode) { |
| switch(NodeOpcode) { |
| default: return false; |
| case ISD::AND: |
| case ISD::OR: |
| return true; |
| } |
| } |
| |
| /// getBCCForSetCC - Returns the PowerPC condition branch mnemonic corresponding |
| /// to Condition. |
| static unsigned getBCCForSetCC(ISD::CondCode CC) { |
| switch (CC) { |
| default: assert(0 && "Unknown condition!"); abort(); |
| case ISD::SETEQ: return PPC::BEQ; |
| case ISD::SETNE: return PPC::BNE; |
| case ISD::SETULT: |
| case ISD::SETLT: return PPC::BLT; |
| case ISD::SETULE: |
| case ISD::SETLE: return PPC::BLE; |
| case ISD::SETUGT: |
| case ISD::SETGT: return PPC::BGT; |
| case ISD::SETUGE: |
| case ISD::SETGE: return PPC::BGE; |
| } |
| return 0; |
| } |
| |
| /// getCRIdxForSetCC - Return the index of the condition register field |
| /// associated with the SetCC condition, and whether or not the field is |
| /// treated as inverted. That is, lt = 0; ge = 0 inverted. |
| static unsigned getCRIdxForSetCC(ISD::CondCode CC, bool& Inv) { |
| switch (CC) { |
| default: assert(0 && "Unknown condition!"); abort(); |
| case ISD::SETULT: |
| case ISD::SETLT: Inv = false; return 0; |
| case ISD::SETUGE: |
| case ISD::SETGE: Inv = true; return 0; |
| case ISD::SETUGT: |
| case ISD::SETGT: Inv = false; return 1; |
| case ISD::SETULE: |
| case ISD::SETLE: Inv = true; return 1; |
| case ISD::SETEQ: Inv = false; return 2; |
| case ISD::SETNE: Inv = true; return 2; |
| } |
| return 0; |
| } |
| |
| /// IndexedOpForOp - Return the indexed variant for each of the PowerPC load |
| /// and store immediate instructions. |
| static unsigned IndexedOpForOp(unsigned Opcode) { |
| switch(Opcode) { |
| default: assert(0 && "Unknown opcode!"); abort(); |
| case PPC::LBZ: return PPC::LBZX; case PPC::STB: return PPC::STBX; |
| case PPC::LHZ: return PPC::LHZX; case PPC::STH: return PPC::STHX; |
| case PPC::LHA: return PPC::LHAX; case PPC::STW: return PPC::STWX; |
| case PPC::LWZ: return PPC::LWZX; case PPC::STFS: return PPC::STFSX; |
| case PPC::LFS: return PPC::LFSX; case PPC::STFD: return PPC::STFDX; |
| case PPC::LFD: return PPC::LFDX; |
| } |
| return 0; |
| } |
| |
| // Structure used to return the necessary information to codegen an SDIV as |
| // a multiply. |
| struct ms { |
| int m; // magic number |
| int s; // shift amount |
| }; |
| |
| struct mu { |
| unsigned int m; // magic number |
| int a; // add indicator |
| int s; // shift amount |
| }; |
| |
| /// magic - calculate the magic numbers required to codegen an integer sdiv as |
| /// a sequence of multiply and shifts. Requires that the divisor not be 0, 1, |
| /// or -1. |
| static struct ms magic(int d) { |
| int p; |
| unsigned int ad, anc, delta, q1, r1, q2, r2, t; |
| const unsigned int two31 = 0x80000000U; |
| struct ms mag; |
| |
| ad = abs(d); |
| t = two31 + ((unsigned int)d >> 31); |
| anc = t - 1 - t%ad; // absolute value of nc |
| p = 31; // initialize p |
| q1 = two31/anc; // initialize q1 = 2p/abs(nc) |
| r1 = two31 - q1*anc; // initialize r1 = rem(2p,abs(nc)) |
| q2 = two31/ad; // initialize q2 = 2p/abs(d) |
| r2 = two31 - q2*ad; // initialize r2 = rem(2p,abs(d)) |
| do { |
| p = p + 1; |
| q1 = 2*q1; // update q1 = 2p/abs(nc) |
| r1 = 2*r1; // update r1 = rem(2p/abs(nc)) |
| if (r1 >= anc) { // must be unsigned comparison |
| q1 = q1 + 1; |
| r1 = r1 - anc; |
| } |
| q2 = 2*q2; // update q2 = 2p/abs(d) |
| r2 = 2*r2; // update r2 = rem(2p/abs(d)) |
| if (r2 >= ad) { // must be unsigned comparison |
| q2 = q2 + 1; |
| r2 = r2 - ad; |
| } |
| delta = ad - r2; |
| } while (q1 < delta || (q1 == delta && r1 == 0)); |
| |
| mag.m = q2 + 1; |
| if (d < 0) mag.m = -mag.m; // resulting magic number |
| mag.s = p - 32; // resulting shift |
| return mag; |
| } |
| |
| /// magicu - calculate the magic numbers required to codegen an integer udiv as |
| /// a sequence of multiply, add and shifts. Requires that the divisor not be 0. |
| static struct mu magicu(unsigned d) |
| { |
| int p; |
| unsigned int nc, delta, q1, r1, q2, r2; |
| struct mu magu; |
| magu.a = 0; // initialize "add" indicator |
| nc = - 1 - (-d)%d; |
| p = 31; // initialize p |
| q1 = 0x80000000/nc; // initialize q1 = 2p/nc |
| r1 = 0x80000000 - q1*nc; // initialize r1 = rem(2p,nc) |
| q2 = 0x7FFFFFFF/d; // initialize q2 = (2p-1)/d |
| r2 = 0x7FFFFFFF - q2*d; // initialize r2 = rem((2p-1),d) |
| do { |
| p = p + 1; |
| if (r1 >= nc - r1 ) { |
| q1 = 2*q1 + 1; // update q1 |
| r1 = 2*r1 - nc; // update r1 |
| } |
| else { |
| q1 = 2*q1; // update q1 |
| r1 = 2*r1; // update r1 |
| } |
| if (r2 + 1 >= d - r2) { |
| if (q2 >= 0x7FFFFFFF) magu.a = 1; |
| q2 = 2*q2 + 1; // update q2 |
| r2 = 2*r2 + 1 - d; // update r2 |
| } |
| else { |
| if (q2 >= 0x80000000) magu.a = 1; |
| q2 = 2*q2; // update q2 |
| r2 = 2*r2 + 1; // update r2 |
| } |
| delta = d - 1 - r2; |
| } while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0))); |
| magu.m = q2 + 1; // resulting magic number |
| magu.s = p - 32; // resulting shift |
| return magu; |
| } |
| } |
| |
| /// BuildSDIVSequence - Given an ISD::SDIV node expressing a divide by constant, |
| /// return a DAG expression to select that will generate the same value by |
| /// multiplying by a magic number. See: |
| /// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html> |
| SDOperand ISel::BuildSDIVSequence(SDOperand N) { |
| int d = (int)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended(); |
| ms magics = magic(d); |
| // Multiply the numerator (operand 0) by the magic value |
| SDOperand Q = ISelDAG->getNode(ISD::MULHS, MVT::i32, N.getOperand(0), |
| ISelDAG->getConstant(magics.m, MVT::i32)); |
| // If d > 0 and m < 0, add the numerator |
| if (d > 0 && magics.m < 0) |
| Q = ISelDAG->getNode(ISD::ADD, MVT::i32, Q, N.getOperand(0)); |
| // If d < 0 and m > 0, subtract the numerator. |
| if (d < 0 && magics.m > 0) |
| Q = ISelDAG->getNode(ISD::SUB, MVT::i32, Q, N.getOperand(0)); |
| // Shift right algebraic if shift value is nonzero |
| if (magics.s > 0) |
| Q = ISelDAG->getNode(ISD::SRA, MVT::i32, Q, |
| ISelDAG->getConstant(magics.s, MVT::i32)); |
| // Extract the sign bit and add it to the quotient |
| SDOperand T = |
| ISelDAG->getNode(ISD::SRL, MVT::i32, Q, ISelDAG->getConstant(31, MVT::i32)); |
| return ISelDAG->getNode(ISD::ADD, MVT::i32, Q, T); |
| } |
| |
| /// BuildUDIVSequence - Given an ISD::UDIV node expressing a divide by constant, |
| /// return a DAG expression to select that will generate the same value by |
| /// multiplying by a magic number. See: |
| /// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html> |
| SDOperand ISel::BuildUDIVSequence(SDOperand N) { |
| unsigned d = |
| (unsigned)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended(); |
| mu magics = magicu(d); |
| // Multiply the numerator (operand 0) by the magic value |
| SDOperand Q = ISelDAG->getNode(ISD::MULHU, MVT::i32, N.getOperand(0), |
| ISelDAG->getConstant(magics.m, MVT::i32)); |
| if (magics.a == 0) { |
| Q = ISelDAG->getNode(ISD::SRL, MVT::i32, Q, |
| ISelDAG->getConstant(magics.s, MVT::i32)); |
| } else { |
| SDOperand NPQ = ISelDAG->getNode(ISD::SUB, MVT::i32, N.getOperand(0), Q); |
| NPQ = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ, |
| ISelDAG->getConstant(1, MVT::i32)); |
| NPQ = ISelDAG->getNode(ISD::ADD, MVT::i32, NPQ, Q); |
| Q = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ, |
| ISelDAG->getConstant(magics.s-1, MVT::i32)); |
| } |
| return Q; |
| } |
| |
| /// getGlobalBaseReg - Output the instructions required to put the |
| /// base address to use for accessing globals into a register. |
| /// |
| unsigned ISel::getGlobalBaseReg() { |
| if (!GlobalBaseInitialized) { |
| // Insert the set of GlobalBaseReg into the first MBB of the function |
| MachineBasicBlock &FirstMBB = BB->getParent()->front(); |
| MachineBasicBlock::iterator MBBI = FirstMBB.begin(); |
| GlobalBaseReg = MakeIntReg(); |
| BuildMI(FirstMBB, MBBI, PPC::MovePCtoLR, 0, PPC::LR); |
| BuildMI(FirstMBB, MBBI, PPC::MFLR, 1, GlobalBaseReg); |
| GlobalBaseInitialized = true; |
| } |
| return GlobalBaseReg; |
| } |
| |
| /// MoveCRtoGPR - Move CCReg[Idx] to the least significant bit of Result. If |
| /// Inv is true, then invert the result. |
| void ISel::MoveCRtoGPR(unsigned CCReg, ISD::CondCode CC, unsigned Result){ |
| bool Inv; |
| unsigned IntCR = MakeIntReg(); |
| unsigned Idx = getCRIdxForSetCC(CC, Inv); |
| BuildMI(BB, PPC::MCRF, 1, PPC::CR7).addReg(CCReg); |
| bool GPOpt = |
| TLI.getTargetMachine().getSubtarget<PPCSubtarget>().isGigaProcessor(); |
| if (GPOpt) |
| BuildMI(BB, PPC::MFOCRF, 1, IntCR).addReg(PPC::CR7); |
| else |
| BuildMI(BB, PPC::MFCR, 0, IntCR); |
| if (Inv) { |
| unsigned Tmp1 = MakeIntReg(); |
| BuildMI(BB, PPC::RLWINM, 4, Tmp1).addReg(IntCR).addImm(32-(3-Idx)) |
| .addImm(31).addImm(31); |
| BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp1).addImm(1); |
| } else { |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(IntCR).addImm(32-(3-Idx)) |
| .addImm(31).addImm(31); |
| } |
| } |
| |
| /// SelectBitfieldInsert - turn an or of two masked values into |
| /// the rotate left word immediate then mask insert (rlwimi) instruction. |
| /// Returns true on success, false if the caller still needs to select OR. |
| /// |
| /// Patterns matched: |
| /// 1. or shl, and 5. or and, and |
| /// 2. or and, shl 6. or shl, shr |
| /// 3. or shr, and 7. or shr, shl |
| /// 4. or and, shr |
| bool ISel::SelectBitfieldInsert(SDOperand OR, unsigned Result) { |
| bool IsRotate = false; |
| unsigned TgtMask = 0xFFFFFFFF, InsMask = 0xFFFFFFFF, Amount = 0; |
| unsigned Value; |
| |
| SDOperand Op0 = OR.getOperand(0); |
| SDOperand Op1 = OR.getOperand(1); |
| |
| unsigned Op0Opc = Op0.getOpcode(); |
| unsigned Op1Opc = Op1.getOpcode(); |
| |
| // Verify that we have the correct opcodes |
| if (ISD::SHL != Op0Opc && ISD::SRL != Op0Opc && ISD::AND != Op0Opc) |
| return false; |
| if (ISD::SHL != Op1Opc && ISD::SRL != Op1Opc && ISD::AND != Op1Opc) |
| return false; |
| |
| // Generate Mask value for Target |
| if (isIntImmediate(Op0.getOperand(1), Value)) { |
| switch(Op0Opc) { |
| case ISD::SHL: TgtMask <<= Value; break; |
| case ISD::SRL: TgtMask >>= Value; break; |
| case ISD::AND: TgtMask &= Value; break; |
| } |
| } else { |
| return false; |
| } |
| |
| // Generate Mask value for Insert |
| if (isIntImmediate(Op1.getOperand(1), Value)) { |
| switch(Op1Opc) { |
| case ISD::SHL: |
| Amount = Value; |
| InsMask <<= Amount; |
| if (Op0Opc == ISD::SRL) IsRotate = true; |
| break; |
| case ISD::SRL: |
| Amount = Value; |
| InsMask >>= Amount; |
| Amount = 32-Amount; |
| if (Op0Opc == ISD::SHL) IsRotate = true; |
| break; |
| case ISD::AND: |
| InsMask &= Value; |
| break; |
| } |
| } else { |
| return false; |
| } |
| |
| unsigned Tmp3 = 0; |
| |
| // If both of the inputs are ANDs and one of them has a logical shift by |
| // constant as its input, make that the inserted value so that we can combine |
| // the shift into the rotate part of the rlwimi instruction |
| if (Op0Opc == ISD::AND && Op1Opc == ISD::AND) { |
| if (Op1.getOperand(0).getOpcode() == ISD::SHL || |
| Op1.getOperand(0).getOpcode() == ISD::SRL) { |
| if (isIntImmediate(Op1.getOperand(0).getOperand(1), Value)) { |
| Amount = Op1.getOperand(0).getOpcode() == ISD::SHL ? |
| Value : 32 - Value; |
| Tmp3 = SelectExpr(Op1.getOperand(0).getOperand(0)); |
| } |
| } else if (Op0.getOperand(0).getOpcode() == ISD::SHL || |
| Op0.getOperand(0).getOpcode() == ISD::SRL) { |
| if (isIntImmediate(Op0.getOperand(0).getOperand(1), Value)) { |
| std::swap(Op0, Op1); |
| std::swap(TgtMask, InsMask); |
| Amount = Op1.getOperand(0).getOpcode() == ISD::SHL ? |
| Value : 32 - Value; |
| Tmp3 = SelectExpr(Op1.getOperand(0).getOperand(0)); |
| } |
| } |
| } |
| |
| // Verify that the Target mask and Insert mask together form a full word mask |
| // and that the Insert mask is a run of set bits (which implies both are runs |
| // of set bits). Given that, Select the arguments and generate the rlwimi |
| // instruction. |
| unsigned MB, ME; |
| if (((TgtMask & InsMask) == 0) && isRunOfOnes(InsMask, MB, ME)) { |
| unsigned Tmp1, Tmp2; |
| bool fullMask = (TgtMask ^ InsMask) == 0xFFFFFFFF; |
| // Check for rotlwi / rotrwi here, a special case of bitfield insert |
| // where both bitfield halves are sourced from the same value. |
| if (IsRotate && fullMask && |
| OR.getOperand(0).getOperand(0) == OR.getOperand(1).getOperand(0)) { |
| Tmp1 = SelectExpr(OR.getOperand(0).getOperand(0)); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(Amount) |
| .addImm(0).addImm(31); |
| return true; |
| } |
| if (Op0Opc == ISD::AND && fullMask) |
| Tmp1 = SelectExpr(Op0.getOperand(0)); |
| else |
| Tmp1 = SelectExpr(Op0); |
| Tmp2 = Tmp3 ? Tmp3 : SelectExpr(Op1.getOperand(0)); |
| BuildMI(BB, PPC::RLWIMI, 5, Result).addReg(Tmp1).addReg(Tmp2) |
| .addImm(Amount).addImm(MB).addImm(ME); |
| return true; |
| } |
| return false; |
| } |
| |
| /// FoldIfWideZeroExtend - 32 bit PowerPC implicit masks shift amounts to the |
| /// low six bits. If the shift amount is an ISD::AND node with a mask that is |
| /// wider than the implicit mask, then we can get rid of the AND and let the |
| /// shift do the mask. |
| unsigned ISel::FoldIfWideZeroExtend(SDOperand N) { |
| unsigned C; |
| if (isOpcWithIntImmediate(N, ISD::AND, C) && isMask_32(C) && C > 63) |
| return SelectExpr(N.getOperand(0)); |
| else |
| return SelectExpr(N); |
| } |
| |
| unsigned ISel::SelectCC(SDOperand LHS, SDOperand RHS, ISD::CondCode CC) { |
| unsigned Result, Tmp1, Tmp2; |
| bool AlreadySelected = false; |
| |
| // Allocate a condition register for this expression |
| Result = RegMap->createVirtualRegister(PPC::CRRCRegisterClass); |
| |
| // Use U to determine whether the SETCC immediate range is signed or not. |
| bool U = ISD::isUnsignedIntSetCC(CC); |
| if (isIntImmediate(RHS, Tmp2) && |
| ((U && isUInt16(Tmp2)) || (!U && isInt16(Tmp2)))) { |
| Tmp2 = Lo16(Tmp2); |
| // For comparisons against zero, we can implicity set CR0 if a recording |
| // variant (e.g. 'or.' instead of 'or') of the instruction that defines |
| // operand zero of the SetCC node is available. |
| if (Tmp2 == 0 && |
| NodeHasRecordingVariant(LHS.getOpcode()) && LHS.Val->hasOneUse()) { |
| RecordSuccess = false; |
| Tmp1 = SelectExpr(LHS, true); |
| if (RecordSuccess) { |
| ++Recorded; |
| BuildMI(BB, PPC::MCRF, 1, Result).addReg(PPC::CR0); |
| return Result; |
| } |
| AlreadySelected = true; |
| } |
| // If we could not implicitly set CR0, then emit a compare immediate |
| // instead. |
| if (!AlreadySelected) Tmp1 = SelectExpr(LHS); |
| if (U) |
| BuildMI(BB, PPC::CMPLWI, 2, Result).addReg(Tmp1).addImm(Tmp2); |
| else |
| BuildMI(BB, PPC::CMPWI, 2, Result).addReg(Tmp1).addSImm(Tmp2); |
| } else { |
| unsigned CompareOpc; |
| if (MVT::isInteger(LHS.getValueType())) |
| CompareOpc = U ? PPC::CMPLW : PPC::CMPW; |
| else if (LHS.getValueType() == MVT::f32) |
| CompareOpc = PPC::FCMPUS; |
| else |
| CompareOpc = PPC::FCMPUD; |
| Tmp1 = SelectExpr(LHS); |
| Tmp2 = SelectExpr(RHS); |
| BuildMI(BB, CompareOpc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| } |
| return Result; |
| } |
| |
| /// Check to see if the load is a constant offset from a base register. |
| unsigned ISel::SelectAddr(SDOperand N, unsigned& Reg, int& offset) |
| { |
| unsigned imm = 0, opcode = N.getOpcode(); |
| if (N.getOpcode() == ISD::ADD) { |
| bool isFrame = N.getOperand(0).getOpcode() == ISD::FrameIndex; |
| if (isIntImmediate(N.getOperand(1), imm) && isInt16(imm)) { |
| offset = Lo16(imm); |
| if (isFrame) { |
| ++FrameOff; |
| Reg = cast<FrameIndexSDNode>(N.getOperand(0))->getIndex(); |
| return 1; |
| } else { |
| Reg = SelectExpr(N.getOperand(0)); |
| return 0; |
| } |
| } else { |
| Reg = SelectExpr(N.getOperand(0)); |
| offset = SelectExpr(N.getOperand(1)); |
| return 2; |
| } |
| } |
| // Now check if we're dealing with a global, and whether or not we should emit |
| // an optimized load or store for statics. |
| if(GlobalAddressSDNode *GN = dyn_cast<GlobalAddressSDNode>(N)) { |
| GlobalValue *GV = GN->getGlobal(); |
| if (!GV->hasWeakLinkage() && !GV->isExternal()) { |
| unsigned GlobalHi = MakeIntReg(); |
| if (PICEnabled) |
| BuildMI(BB, PPC::ADDIS, 2, GlobalHi).addReg(getGlobalBaseReg()) |
| .addGlobalAddress(GV); |
| else |
| BuildMI(BB, PPC::LIS, 1, GlobalHi).addGlobalAddress(GV); |
| Reg = GlobalHi; |
| offset = 0; |
| return 3; |
| } |
| } |
| Reg = SelectExpr(N); |
| offset = 0; |
| return 0; |
| } |
| |
| void ISel::SelectBranchCC(SDOperand N) |
| { |
| MachineBasicBlock *Dest = |
| cast<BasicBlockSDNode>(N.getOperand(4))->getBasicBlock(); |
| |
| Select(N.getOperand(0)); //chain |
| ISD::CondCode CC = cast<CondCodeSDNode>(N.getOperand(1))->get(); |
| unsigned CCReg = SelectCC(N.getOperand(2), N.getOperand(3), CC); |
| unsigned Opc = getBCCForSetCC(CC); |
| |
| // If this is a two way branch, then grab the fallthrough basic block argument |
| // and build a PowerPC branch pseudo-op, suitable for long branch conversion |
| // if necessary by the branch selection pass. Otherwise, emit a standard |
| // conditional branch. |
| if (N.getOpcode() == ISD::BRTWOWAY_CC) { |
| MachineBasicBlock *Fallthrough = |
| cast<BasicBlockSDNode>(N.getOperand(5))->getBasicBlock(); |
| BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc) |
| .addMBB(Dest).addMBB(Fallthrough); |
| BuildMI(BB, PPC::B, 1).addMBB(Fallthrough); |
| } else { |
| // Iterate to the next basic block |
| ilist<MachineBasicBlock>::iterator It = BB; |
| ++It; |
| |
| // If the fallthrough path is off the end of the function, which would be |
| // undefined behavior, set it to be the same as the current block because |
| // we have nothing better to set it to, and leaving it alone will cause the |
| // PowerPC Branch Selection pass to crash. |
| if (It == BB->getParent()->end()) It = Dest; |
| BuildMI(BB, PPC::COND_BRANCH, 4).addReg(CCReg).addImm(Opc) |
| .addMBB(Dest).addMBB(It); |
| } |
| return; |
| } |
| |
| // SelectIntImmediateExpr - Choose code for opcodes with immediate value. |
| bool ISel::SelectIntImmediateExpr(SDOperand N, unsigned Result, |
| unsigned OCHi, unsigned OCLo, |
| bool IsArithmetic, bool Negate) { |
| // check constant |
| ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N.getOperand(1)); |
| // exit if not a constant |
| if (!CN) return false; |
| // extract immediate |
| unsigned C = (unsigned)CN->getValue(); |
| // negate if required (ISD::SUB) |
| if (Negate) C = -C; |
| // get the hi and lo portions of constant |
| unsigned Hi = IsArithmetic ? HA16(C) : Hi16(C); |
| unsigned Lo = Lo16(C); |
| // assume no intermediate result from lo instruction (same as final result) |
| unsigned Tmp = Result; |
| // check if two instructions are needed |
| if (Hi && Lo) { |
| // exit if usage indicates it would be better to load immediate into a |
| // register |
| if (CN->use_size() > 2) return false; |
| // need intermediate result for two instructions |
| Tmp = MakeIntReg(); |
| } |
| // get first operand |
| unsigned Opr0 = SelectExpr(N.getOperand(0)); |
| // is a lo instruction needed |
| if (Lo) { |
| // generate instruction for lo portion |
| BuildMI(BB, OCLo, 2, Tmp).addReg(Opr0).addImm(Lo); |
| // need to switch out first operand for hi instruction |
| Opr0 = Tmp; |
| } |
| // is a hi instruction needed |
| if (Hi) { |
| // generate instruction for hi portion |
| BuildMI(BB, OCHi, 2, Result).addReg(Opr0).addImm(Hi); |
| } |
| return true; |
| } |
| |
| unsigned ISel::SelectExpr(SDOperand N, bool Recording) { |
| unsigned Result; |
| unsigned Tmp1, Tmp2, Tmp3; |
| unsigned Opc = 0; |
| unsigned opcode = N.getOpcode(); |
| |
| SDNode *Node = N.Val; |
| MVT::ValueType DestType = N.getValueType(); |
| |
| if (Node->getOpcode() == ISD::CopyFromReg) { |
| unsigned Reg = cast<RegisterSDNode>(Node->getOperand(1))->getReg(); |
| // Just use the specified register as our input. |
| if (MRegisterInfo::isVirtualRegister(Reg) || Reg == PPC::R1) |
| return Reg; |
| } |
| |
| unsigned &Reg = ExprMap[N]; |
| if (Reg) return Reg; |
| |
| switch (N.getOpcode()) { |
| default: |
| Reg = Result = (N.getValueType() != MVT::Other) ? |
| MakeReg(N.getValueType()) : 1; |
| break; |
| case ISD::AssertSext: |
| case ISD::AssertZext: |
| // Don't allocate a vreg for these nodes. |
| return Reg = SelectExpr(N.getOperand(0)); |
| case ISD::TAILCALL: |
| case ISD::CALL: |
| // If this is a call instruction, make sure to prepare ALL of the result |
| // values as well as the chain. |
| if (Node->getNumValues() == 1) |
| Reg = Result = 1; // Void call, just a chain. |
| else { |
| Result = MakeReg(Node->getValueType(0)); |
| ExprMap[N.getValue(0)] = Result; |
| for (unsigned i = 1, e = N.Val->getNumValues()-1; i != e; ++i) |
| ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i)); |
| ExprMap[SDOperand(Node, Node->getNumValues()-1)] = 1; |
| } |
| break; |
| case ISD::ADD_PARTS: |
| case ISD::SUB_PARTS: |
| Result = MakeReg(Node->getValueType(0)); |
| ExprMap[N.getValue(0)] = Result; |
| for (unsigned i = 1, e = N.Val->getNumValues(); i != e; ++i) |
| ExprMap[N.getValue(i)] = MakeReg(Node->getValueType(i)); |
| break; |
| } |
| |
| switch (opcode) { |
| default: |
| Node->dump(); std::cerr << '\n'; |
| assert(0 && "Node not handled!\n"); |
| case PPCISD::FSEL: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(2)); |
| |
| // Extend the comparison to 64-bits if needed. |
| if (N.getOperand(0).getValueType() == MVT::f32) { |
| unsigned Tmp1New = MakeReg(MVT::f64); |
| BuildMI(BB, PPC::FMRSD, 1, Tmp1New).addReg(Tmp1); |
| Tmp1 = Tmp1New; |
| } |
| |
| Opc = N.Val->getValueType(0) == MVT::f32 ? PPC::FSELS : PPC::FSELD; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| return Result; |
| case PPCISD::FCFID: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::FCFID, 1, Result).addReg(Tmp1); |
| return Result; |
| case PPCISD::FCTIDZ: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::FCTIDZ, 1, Result).addReg(Tmp1); |
| return Result; |
| case PPCISD::FCTIWZ: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::FCTIWZ, 1, Result).addReg(Tmp1); |
| return Result; |
| case ISD::UNDEF: |
| if (Node->getValueType(0) == MVT::i32) |
| BuildMI(BB, PPC::IMPLICIT_DEF_GPR, 0, Result); |
| else if (Node->getValueType(0) == MVT::f32) |
| BuildMI(BB, PPC::IMPLICIT_DEF_F4, 0, Result); |
| else |
| BuildMI(BB, PPC::IMPLICIT_DEF_F8, 0, Result); |
| return Result; |
| case ISD::DYNAMIC_STACKALLOC: |
| // Generate both result values. FIXME: Need a better commment here? |
| if (Result != 1) |
| ExprMap[N.getValue(1)] = 1; |
| else |
| Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType()); |
| |
| // FIXME: We are currently ignoring the requested alignment for handling |
| // greater than the stack alignment. This will need to be revisited at some |
| // point. Align = N.getOperand(2); |
| if (!isa<ConstantSDNode>(N.getOperand(2)) || |
| cast<ConstantSDNode>(N.getOperand(2))->getValue() != 0) { |
| std::cerr << "Cannot allocate stack object with greater alignment than" |
| << " the stack alignment yet!"; |
| abort(); |
| } |
| Select(N.getOperand(0)); |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| // Subtract size from stack pointer, thereby allocating some space. |
| BuildMI(BB, PPC::SUBF, 2, PPC::R1).addReg(Tmp1).addReg(PPC::R1); |
| // Put a pointer to the space into the result register by copying the SP |
| BuildMI(BB, PPC::OR4, 2, Result).addReg(PPC::R1).addReg(PPC::R1); |
| return Result; |
| |
| case ISD::ConstantPool: |
| Tmp1 = BB->getParent()->getConstantPool()-> |
| getConstantPoolIndex(cast<ConstantPoolSDNode>(N)->get()); |
| Tmp2 = MakeIntReg(); |
| if (PICEnabled) |
| BuildMI(BB, PPC::ADDIS, 2, Tmp2).addReg(getGlobalBaseReg()) |
| .addConstantPoolIndex(Tmp1); |
| else |
| BuildMI(BB, PPC::LIS, 1, Tmp2).addConstantPoolIndex(Tmp1); |
| BuildMI(BB, PPC::LA, 2, Result).addReg(Tmp2).addConstantPoolIndex(Tmp1); |
| return Result; |
| |
| case ISD::FrameIndex: |
| Tmp1 = cast<FrameIndexSDNode>(N)->getIndex(); |
| addFrameReference(BuildMI(BB, PPC::ADDI, 2, Result), (int)Tmp1, 0, false); |
| return Result; |
| |
| case ISD::GlobalAddress: { |
| GlobalValue *GV = cast<GlobalAddressSDNode>(N)->getGlobal(); |
| Tmp1 = MakeIntReg(); |
| if (PICEnabled) |
| BuildMI(BB, PPC::ADDIS, 2, Tmp1).addReg(getGlobalBaseReg()) |
| .addGlobalAddress(GV); |
| else |
| BuildMI(BB, PPC::LIS, 1, Tmp1).addGlobalAddress(GV); |
| if (GV->hasWeakLinkage() || GV->isExternal()) { |
| BuildMI(BB, PPC::LWZ, 2, Result).addGlobalAddress(GV).addReg(Tmp1); |
| } else { |
| BuildMI(BB, PPC::LA, 2, Result).addReg(Tmp1).addGlobalAddress(GV); |
| } |
| return Result; |
| } |
| |
| case ISD::LOAD: |
| case ISD::EXTLOAD: |
| case ISD::ZEXTLOAD: |
| case ISD::SEXTLOAD: { |
| MVT::ValueType TypeBeingLoaded = (ISD::LOAD == opcode) ? |
| Node->getValueType(0) : cast<VTSDNode>(Node->getOperand(3))->getVT(); |
| bool sext = (ISD::SEXTLOAD == opcode); |
| |
| // Make sure we generate both values. |
| if (Result != 1) |
| ExprMap[N.getValue(1)] = 1; // Generate the token |
| else |
| Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType()); |
| |
| SDOperand Chain = N.getOperand(0); |
| SDOperand Address = N.getOperand(1); |
| Select(Chain); |
| |
| switch (TypeBeingLoaded) { |
| default: Node->dump(); assert(0 && "Cannot load this type!"); |
| case MVT::i1: Opc = PPC::LBZ; break; |
| case MVT::i8: Opc = PPC::LBZ; break; |
| case MVT::i16: Opc = sext ? PPC::LHA : PPC::LHZ; break; |
| case MVT::i32: Opc = PPC::LWZ; break; |
| case MVT::f32: Opc = PPC::LFS; break; |
| case MVT::f64: Opc = PPC::LFD; break; |
| } |
| |
| if (ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Address)) { |
| Tmp1 = MakeIntReg(); |
| unsigned CPI = BB->getParent()->getConstantPool()-> |
| getConstantPoolIndex(CP->get()); |
| if (PICEnabled) |
| BuildMI(BB, PPC::ADDIS, 2, Tmp1).addReg(getGlobalBaseReg()) |
| .addConstantPoolIndex(CPI); |
| else |
| BuildMI(BB, PPC::LIS, 1, Tmp1).addConstantPoolIndex(CPI); |
| BuildMI(BB, Opc, 2, Result).addConstantPoolIndex(CPI).addReg(Tmp1); |
| } else if (Address.getOpcode() == ISD::FrameIndex) { |
| Tmp1 = cast<FrameIndexSDNode>(Address)->getIndex(); |
| addFrameReference(BuildMI(BB, Opc, 2, Result), (int)Tmp1); |
| } else { |
| int offset; |
| switch(SelectAddr(Address, Tmp1, offset)) { |
| default: assert(0 && "Unhandled return value from SelectAddr"); |
| case 0: // imm offset, no frame, no index |
| BuildMI(BB, Opc, 2, Result).addSImm(offset).addReg(Tmp1); |
| break; |
| case 1: // imm offset + frame index |
| addFrameReference(BuildMI(BB, Opc, 2, Result), (int)Tmp1, offset); |
| break; |
| case 2: // base+index addressing |
| Opc = IndexedOpForOp(Opc); |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(offset); |
| break; |
| case 3: { |
| GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Address); |
| GlobalValue *GV = GN->getGlobal(); |
| BuildMI(BB, Opc, 2, Result).addGlobalAddress(GV).addReg(Tmp1); |
| } |
| } |
| } |
| return Result; |
| } |
| |
| case ISD::TAILCALL: |
| case ISD::CALL: { |
| unsigned GPR_idx = 0, FPR_idx = 0; |
| static const unsigned GPR[] = { |
| PPC::R3, PPC::R4, PPC::R5, PPC::R6, |
| PPC::R7, PPC::R8, PPC::R9, PPC::R10, |
| }; |
| static const unsigned FPR[] = { |
| PPC::F1, PPC::F2, PPC::F3, PPC::F4, PPC::F5, PPC::F6, PPC::F7, |
| PPC::F8, PPC::F9, PPC::F10, PPC::F11, PPC::F12, PPC::F13 |
| }; |
| |
| // Lower the chain for this call. |
| Select(N.getOperand(0)); |
| ExprMap[N.getValue(Node->getNumValues()-1)] = 1; |
| |
| MachineInstr *CallMI; |
| // Emit the correct call instruction based on the type of symbol called. |
| if (GlobalAddressSDNode *GASD = |
| dyn_cast<GlobalAddressSDNode>(N.getOperand(1))) { |
| CallMI = BuildMI(PPC::CALLpcrel, 1).addGlobalAddress(GASD->getGlobal(), |
| true); |
| } else if (ExternalSymbolSDNode *ESSDN = |
| dyn_cast<ExternalSymbolSDNode>(N.getOperand(1))) { |
| CallMI = BuildMI(PPC::CALLpcrel, 1).addExternalSymbol(ESSDN->getSymbol(), |
| true); |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::MTCTR, 1).addReg(Tmp1); |
| BuildMI(BB, PPC::OR4, 2, PPC::R12).addReg(Tmp1).addReg(Tmp1); |
| CallMI = BuildMI(PPC::CALLindirect, 3).addImm(20).addImm(0) |
| .addReg(PPC::R12); |
| } |
| |
| // Load the register args to virtual regs |
| std::vector<unsigned> ArgVR; |
| for(int i = 2, e = Node->getNumOperands(); i < e; ++i) |
| ArgVR.push_back(SelectExpr(N.getOperand(i))); |
| |
| // Copy the virtual registers into the appropriate argument register |
| for(int i = 0, e = ArgVR.size(); i < e; ++i) { |
| switch(N.getOperand(i+2).getValueType()) { |
| default: Node->dump(); assert(0 && "Unknown value type for call"); |
| case MVT::i32: |
| assert(GPR_idx < 8 && "Too many int args"); |
| if (N.getOperand(i+2).getOpcode() != ISD::UNDEF) { |
| BuildMI(BB, PPC::OR4,2,GPR[GPR_idx]).addReg(ArgVR[i]).addReg(ArgVR[i]); |
| CallMI->addRegOperand(GPR[GPR_idx], MachineOperand::Use); |
| } |
| ++GPR_idx; |
| break; |
| case MVT::f64: |
| case MVT::f32: |
| assert(FPR_idx < 13 && "Too many fp args"); |
| BuildMI(BB, N.getOperand(i+2).getValueType() == MVT::f32 ? PPC::FMRS : |
| PPC::FMRD, 1, FPR[FPR_idx]).addReg(ArgVR[i]); |
| CallMI->addRegOperand(FPR[FPR_idx], MachineOperand::Use); |
| ++FPR_idx; |
| break; |
| } |
| } |
| |
| // Put the call instruction in the correct place in the MachineBasicBlock |
| BB->push_back(CallMI); |
| |
| switch (Node->getValueType(0)) { |
| default: assert(0 && "Unknown value type for call result!"); |
| case MVT::Other: return 1; |
| case MVT::i32: |
| if (Node->getValueType(1) == MVT::i32) { |
| BuildMI(BB, PPC::OR4, 2, Result+1).addReg(PPC::R3).addReg(PPC::R3); |
| BuildMI(BB, PPC::OR4, 2, Result).addReg(PPC::R4).addReg(PPC::R4); |
| } else { |
| BuildMI(BB, PPC::OR4, 2, Result).addReg(PPC::R3).addReg(PPC::R3); |
| } |
| break; |
| case MVT::f32: |
| BuildMI(BB, PPC::FMRS, 1, Result).addReg(PPC::F1); |
| break; |
| case MVT::f64: |
| BuildMI(BB, PPC::FMRD, 1, Result).addReg(PPC::F1); |
| break; |
| } |
| return Result+N.ResNo; |
| } |
| |
| case ISD::SIGN_EXTEND_INREG: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| switch(cast<VTSDNode>(Node->getOperand(1))->getVT()) { |
| default: Node->dump(); assert(0 && "Unhandled SIGN_EXTEND type"); break; |
| case MVT::i16: |
| BuildMI(BB, PPC::EXTSH, 1, Result).addReg(Tmp1); |
| break; |
| case MVT::i8: |
| BuildMI(BB, PPC::EXTSB, 1, Result).addReg(Tmp1); |
| break; |
| } |
| return Result; |
| |
| case ISD::CopyFromReg: |
| DestType = N.getValue(0).getValueType(); |
| if (Result == 1) |
| Result = ExprMap[N.getValue(0)] = MakeReg(DestType); |
| else |
| ExprMap[N.getValue(1)] = 1; |
| Tmp1 = dyn_cast<RegisterSDNode>(Node->getOperand(1))->getReg(); |
| if (MVT::isInteger(DestType)) |
| BuildMI(BB, PPC::OR4, 2, Result).addReg(Tmp1).addReg(Tmp1); |
| else if (DestType == MVT::f32) |
| BuildMI(BB, PPC::FMRS, 1, Result).addReg(Tmp1); |
| else |
| BuildMI(BB, PPC::FMRD, 1, Result).addReg(Tmp1); |
| return Result; |
| |
| case ISD::SHL: |
| if (isIntImmediate(N.getOperand(1), Tmp2)) { |
| unsigned SH, MB, ME; |
| if (isOpcWithIntImmediate(N.getOperand(0), ISD::AND, Tmp3) && |
| isRotateAndMask(ISD::SHL, Tmp2, Tmp3, true, SH, MB, ME)) { |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(SH) |
| .addImm(MB).addImm(ME); |
| return Result; |
| } |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 &= 0x1F; |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(Tmp2).addImm(0) |
| .addImm(31-Tmp2); |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = FoldIfWideZeroExtend(N.getOperand(1)); |
| BuildMI(BB, PPC::SLW, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| } |
| return Result; |
| |
| case ISD::SRL: |
| if (isIntImmediate(N.getOperand(1), Tmp2)) { |
| unsigned SH, MB, ME; |
| if (isOpcWithIntImmediate(N.getOperand(0), ISD::AND, Tmp3) && |
| isRotateAndMask(ISD::SRL, Tmp2, Tmp3, true, SH, MB, ME)) { |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(SH & 0x1F) |
| .addImm(MB).addImm(ME); |
| return Result; |
| } |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 &= 0x1F; |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm((32-Tmp2) & 0x1F) |
| .addImm(Tmp2).addImm(31); |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = FoldIfWideZeroExtend(N.getOperand(1)); |
| BuildMI(BB, PPC::SRW, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| } |
| return Result; |
| |
| case ISD::SRA: |
| if (isIntImmediate(N.getOperand(1), Tmp2)) { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::SRAWI, 2, Result).addReg(Tmp1).addImm(Tmp2 & 0x1F); |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = FoldIfWideZeroExtend(N.getOperand(1)); |
| BuildMI(BB, PPC::SRAW, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| } |
| return Result; |
| |
| case ISD::CTLZ: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::CNTLZW, 1, Result).addReg(Tmp1); |
| return Result; |
| |
| case ISD::ADD: |
| if (SelectIntImmediateExpr(N, Result, PPC::ADDIS, PPC::ADDI, true)) |
| return Result; |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::ADD4, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::FADD: |
| if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::FMUL && |
| N.getOperand(0).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(1)); |
| Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| return Result; |
| } |
| if (!NoExcessFPPrecision && N.getOperand(1).getOpcode() == ISD::FMUL && |
| N.getOperand(1).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(1).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(0)); |
| Opc = DestType == MVT::f64 ? PPC::FMADD : PPC::FMADDS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| return Result; |
| } |
| Opc = DestType == MVT::f64 ? PPC::FADD : PPC::FADDS; |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::AND: |
| if (isIntImmediate(N.getOperand(1), Tmp2)) { |
| if (isShiftedMask_32(Tmp2) || isShiftedMask_32(~Tmp2)) { |
| unsigned SH, MB, ME; |
| Opc = Recording ? PPC::RLWINMo : PPC::RLWINM; |
| unsigned OprOpc; |
| if (isOprShiftImm(N.getOperand(0), OprOpc, Tmp3) && |
| isRotateAndMask(OprOpc, Tmp3, Tmp2, false, SH, MB, ME)) { |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| isRunOfOnes(Tmp2, MB, ME); |
| SH = 0; |
| } |
| BuildMI(BB, Opc, 4, Result).addReg(Tmp1).addImm(SH) |
| .addImm(MB).addImm(ME); |
| RecordSuccess = true; |
| return Result; |
| } else if (isUInt16(Tmp2)) { |
| Tmp2 = Lo16(Tmp2); |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::ANDIo, 2, Result).addReg(Tmp1).addImm(Tmp2); |
| RecordSuccess = true; |
| return Result; |
| } else if (isUInt16(Tmp2)) { |
| Tmp2 = Hi16(Tmp2); |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::ANDISo, 2, Result).addReg(Tmp1).addImm(Tmp2); |
| RecordSuccess = true; |
| return Result; |
| } |
| } |
| if (isOprNot(N.getOperand(1))) { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1).getOperand(0)); |
| BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| RecordSuccess = false; |
| return Result; |
| } |
| if (isOprNot(N.getOperand(0))) { |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(0)); |
| BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| RecordSuccess = false; |
| return Result; |
| } |
| // emit a regular and |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| Opc = Recording ? PPC::ANDo : PPC::AND; |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| RecordSuccess = true; |
| return Result; |
| |
| case ISD::OR: |
| if (SelectBitfieldInsert(N, Result)) |
| return Result; |
| if (SelectIntImmediateExpr(N, Result, PPC::ORIS, PPC::ORI)) |
| return Result; |
| if (isOprNot(N.getOperand(1))) { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1).getOperand(0)); |
| BuildMI(BB, PPC::ORC, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| RecordSuccess = false; |
| return Result; |
| } |
| if (isOprNot(N.getOperand(0))) { |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(0)); |
| BuildMI(BB, PPC::ORC, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| RecordSuccess = false; |
| return Result; |
| } |
| // emit regular or |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| Opc = Recording ? PPC::ORo : PPC::OR4; |
| RecordSuccess = true; |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::XOR: { |
| // Check for EQV: xor, (xor a, -1), b |
| if (isOprNot(N.getOperand(0))) { |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::EQV, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| } |
| // Check for NOT, NOR, EQV, and NAND: xor (copy, or, xor, and), -1 |
| if (isOprNot(N)) { |
| switch(N.getOperand(0).getOpcode()) { |
| case ISD::OR: |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1)); |
| BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| break; |
| case ISD::AND: |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1)); |
| BuildMI(BB, PPC::NAND, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| break; |
| case ISD::XOR: |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1)); |
| BuildMI(BB, PPC::EQV, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| break; |
| default: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::NOR, 2, Result).addReg(Tmp1).addReg(Tmp1); |
| break; |
| } |
| return Result; |
| } |
| if (SelectIntImmediateExpr(N, Result, PPC::XORIS, PPC::XORI)) |
| return Result; |
| // emit regular xor |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::XOR, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| } |
| |
| case ISD::FSUB: |
| if (!NoExcessFPPrecision && N.getOperand(0).getOpcode() == ISD::FMUL && |
| N.getOperand(0).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(1)); |
| Opc = DestType == MVT::f64 ? PPC::FMSUB : PPC::FMSUBS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| return Result; |
| } |
| if (!NoExcessFPPrecision && N.getOperand(1).getOpcode() == ISD::FMUL && |
| N.getOperand(1).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(1).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(0)); |
| Opc = DestType == MVT::f64 ? PPC::FNMSUB : PPC::FNMSUBS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| return Result; |
| } |
| Opc = DestType == MVT::f64 ? PPC::FSUB : PPC::FSUBS; |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| case ISD::SUB: |
| if (isIntImmediate(N.getOperand(0), Tmp1) && isInt16(Tmp1)) { |
| Tmp1 = Lo16(Tmp1); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| if (0 == Tmp1) |
| BuildMI(BB, PPC::NEG, 1, Result).addReg(Tmp2); |
| else |
| BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp2).addSImm(Tmp1); |
| return Result; |
| } |
| if (SelectIntImmediateExpr(N, Result, PPC::ADDIS, PPC::ADDI, true, true)) |
| return Result; |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp2).addReg(Tmp1); |
| return Result; |
| |
| case ISD::FMUL: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, DestType == MVT::f32 ? PPC::FMULS : PPC::FMUL, 2, |
| Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::MUL: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| if (isIntImmediate(N.getOperand(1), Tmp2) && isInt16(Tmp2)) { |
| Tmp2 = Lo16(Tmp2); |
| BuildMI(BB, PPC::MULLI, 2, Result).addReg(Tmp1).addSImm(Tmp2); |
| } else { |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| BuildMI(BB, PPC::MULLW, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| } |
| return Result; |
| |
| case ISD::MULHS: |
| case ISD::MULHU: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| Opc = (ISD::MULHU == opcode) ? PPC::MULHWU : PPC::MULHW; |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::FDIV: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| switch (DestType) { |
| default: assert(0 && "Unknown type to ISD::FDIV"); break; |
| case MVT::f32: Opc = PPC::FDIVS; break; |
| case MVT::f64: Opc = PPC::FDIV; break; |
| } |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::SDIV: |
| if (isIntImmediate(N.getOperand(1), Tmp3)) { |
| if ((signed)Tmp3 > 0 && isPowerOf2_32(Tmp3)) { |
| Tmp3 = Log2_32(Tmp3); |
| Tmp1 = MakeIntReg(); |
| Tmp2 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3); |
| BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1); |
| return Result; |
| } else if ((signed)Tmp3 < 0 && isPowerOf2_32(-Tmp3)) { |
| Tmp3 = Log2_32(-Tmp3); |
| Tmp2 = SelectExpr(N.getOperand(0)); |
| Tmp1 = MakeIntReg(); |
| unsigned Tmp4 = MakeIntReg(); |
| BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3); |
| BuildMI(BB, PPC::ADDZE, 1, Tmp4).addReg(Tmp1); |
| BuildMI(BB, PPC::NEG, 1, Result).addReg(Tmp4); |
| return Result; |
| } else if (Tmp3) { |
| ExprMap.erase(N); |
| return SelectExpr(BuildSDIVSequence(N)); |
| } |
| } |
| // fall thru |
| case ISD::UDIV: |
| // If this is a divide by constant, we can emit code using some magic |
| // constants to implement it as a multiply instead. |
| if (isIntImmediate(N.getOperand(1), Tmp3) && Tmp3) { |
| ExprMap.erase(N); |
| return SelectExpr(BuildUDIVSequence(N)); |
| } |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| Opc = (ISD::UDIV == opcode) ? PPC::DIVWU : PPC::DIVW; break; |
| BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2); |
| return Result; |
| |
| case ISD::ADD_PARTS: |
| case ISD::SUB_PARTS: { |
| assert(N.getNumOperands() == 4 && N.getValueType() == MVT::i32 && |
| "Not an i64 add/sub!"); |
| unsigned Tmp4 = 0; |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(1)); |
| |
| if (N.getOpcode() == ISD::ADD_PARTS) { |
| bool ME = false, ZE = false; |
| if (isIntImmediate(N.getOperand(3), Tmp3)) { |
| ME = (signed)Tmp3 == -1; |
| ZE = Tmp3 == 0; |
| } |
| |
| if (!ZE && !ME) |
| Tmp4 = SelectExpr(N.getOperand(3)); |
| |
| if (isIntImmediate(N.getOperand(2), Tmp3) && |
| ((signed)Tmp3 >= -32768 || (signed)Tmp3 < 32768)) { |
| // Codegen the low 32 bits of the add. Interestingly, there is no |
| // shifted form of add immediate carrying. |
| BuildMI(BB, PPC::ADDIC, 2, Result).addReg(Tmp1).addSImm(Tmp3); |
| } else { |
| Tmp3 = SelectExpr(N.getOperand(2)); |
| BuildMI(BB, PPC::ADDC, 2, Result).addReg(Tmp1).addReg(Tmp3); |
| } |
| |
| // Codegen the high 32 bits, adding zero, minus one, or the full value |
| // along with the carry flag produced by addc/addic to tmp2. |
| if (ZE) { |
| BuildMI(BB, PPC::ADDZE, 1, Result+1).addReg(Tmp2); |
| } else if (ME) { |
| BuildMI(BB, PPC::ADDME, 1, Result+1).addReg(Tmp2); |
| } else { |
| BuildMI(BB, PPC::ADDE, 2, Result+1).addReg(Tmp2).addReg(Tmp4); |
| } |
| } else { |
| Tmp3 = SelectExpr(N.getOperand(2)); |
| Tmp4 = SelectExpr(N.getOperand(3)); |
| BuildMI(BB, PPC::SUBFC, 2, Result).addReg(Tmp3).addReg(Tmp1); |
| BuildMI(BB, PPC::SUBFE, 2, Result+1).addReg(Tmp4).addReg(Tmp2); |
| } |
| return Result+N.ResNo; |
| } |
| |
| case ISD::SETCC: { |
| ISD::CondCode CC = cast<CondCodeSDNode>(Node->getOperand(2))->get(); |
| if (isIntImmediate(Node->getOperand(1), Tmp3)) { |
| // We can codegen setcc op, imm very efficiently compared to a brcond. |
| // Check for those cases here. |
| // setcc op, 0 |
| if (Tmp3 == 0) { |
| Tmp1 = SelectExpr(Node->getOperand(0)); |
| switch (CC) { |
| default: Node->dump(); assert(0 && "Unhandled SetCC condition");abort(); |
| case ISD::SETEQ: |
| Tmp2 = MakeIntReg(); |
| BuildMI(BB, PPC::CNTLZW, 1, Tmp2).addReg(Tmp1); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp2).addImm(27) |
| .addImm(5).addImm(31); |
| break; |
| case ISD::SETNE: |
| Tmp2 = MakeIntReg(); |
| BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(-1); |
| BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp2).addReg(Tmp1); |
| break; |
| case ISD::SETLT: |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp1).addImm(1) |
| .addImm(31).addImm(31); |
| break; |
| case ISD::SETGT: |
| Tmp2 = MakeIntReg(); |
| Tmp3 = MakeIntReg(); |
| BuildMI(BB, PPC::NEG, 2, Tmp2).addReg(Tmp1); |
| BuildMI(BB, PPC::ANDC, 2, Tmp3).addReg(Tmp2).addReg(Tmp1); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1) |
| .addImm(31).addImm(31); |
| break; |
| } |
| return Result; |
| } else if (Tmp3 == ~0U) { // setcc op, -1 |
| Tmp1 = SelectExpr(Node->getOperand(0)); |
| switch (CC) { |
| default: assert(0 && "Unhandled SetCC condition"); abort(); |
| case ISD::SETEQ: |
| Tmp2 = MakeIntReg(); |
| Tmp3 = MakeIntReg(); |
| BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(1); |
| BuildMI(BB, PPC::LI, 1, Tmp3).addSImm(0); |
| BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp3); |
| break; |
| case ISD::SETNE: |
| Tmp2 = MakeIntReg(); |
| Tmp3 = MakeIntReg(); |
| BuildMI(BB, PPC::NOR, 2, Tmp2).addReg(Tmp1).addReg(Tmp1); |
| BuildMI(BB, PPC::ADDIC, 2, Tmp3).addReg(Tmp2).addSImm(-1); |
| BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp3).addReg(Tmp2); |
| break; |
| case ISD::SETLT: |
| Tmp2 = MakeIntReg(); |
| Tmp3 = MakeIntReg(); |
| BuildMI(BB, PPC::ADDI, 2, Tmp2).addReg(Tmp1).addSImm(1); |
| BuildMI(BB, PPC::AND, 2, Tmp3).addReg(Tmp2).addReg(Tmp1); |
| BuildMI(BB, PPC::RLWINM, 4, Result).addReg(Tmp3).addImm(1) |
| .addImm(31).addImm(31); |
| break; |
| case ISD::SETGT: |
| Tmp2 = MakeIntReg(); |
| BuildMI(BB, PPC::RLWINM, 4, Tmp2).addReg(Tmp1).addImm(1) |
| .addImm(31).addImm(31); |
| BuildMI(BB, PPC::XORI, 2, Result).addReg(Tmp2).addImm(1); |
| break; |
| } |
| return Result; |
| } |
| } |
| |
| unsigned CCReg = SelectCC(N.getOperand(0), N.getOperand(1), CC); |
| MoveCRtoGPR(CCReg, CC, Result); |
| return Result; |
| } |
| |
| case ISD::SELECT_CC: { |
| ISD::CondCode CC = cast<CondCodeSDNode>(N.getOperand(4))->get(); |
| |
| // handle the setcc cases here. select_cc lhs, 0, 1, 0, cc |
| ConstantSDNode *N1C = dyn_cast<ConstantSDNode>(N.getOperand(1)); |
| ConstantSDNode *N2C = dyn_cast<ConstantSDNode>(N.getOperand(2)); |
| ConstantSDNode *N3C = dyn_cast<ConstantSDNode>(N.getOperand(3)); |
| if (N1C && N2C && N3C && N1C->isNullValue() && N3C->isNullValue() && |
| N2C->getValue() == 1ULL && CC == ISD::SETNE) { |
| Tmp1 = SelectExpr(Node->getOperand(0)); |
| Tmp2 = MakeIntReg(); |
| BuildMI(BB, PPC::ADDIC, 2, Tmp2).addReg(Tmp1).addSImm(-1); |
| BuildMI(BB, PPC::SUBFE, 2, Result).addReg(Tmp2).addReg(Tmp1); |
| return Result; |
| } |
| |
| // If the False value only has one use, we can generate better code by |
| // selecting it in the fallthrough basic block rather than here, which |
| // increases register pressure. |
| unsigned TrueValue = SelectExpr(N.getOperand(2)); |
| unsigned FalseValue; |
| |
| // If the false value is simple enough, evaluate it inline in the false |
| // block. |
| if (N.getOperand(3).Val->hasOneUse() && |
| (isa<ConstantSDNode>(N.getOperand(3)) || |
| isa<GlobalAddressSDNode>(N.getOperand(3)))) |
| FalseValue = 0; |
| else |
| FalseValue = SelectExpr(N.getOperand(3)); |
| unsigned CCReg = SelectCC(N.getOperand(0), N.getOperand(1), CC); |
| Opc = getBCCForSetCC(CC); |
| |
| // Create an iterator with which to insert the MBB for copying the false |
| // value and the MBB to hold the PHI instruction for this SetCC. |
| MachineBasicBlock *thisMBB = BB; |
| const BasicBlock *LLVM_BB = BB->getBasicBlock(); |
| ilist<MachineBasicBlock>::iterator It = BB; |
| ++It; |
| |
| // thisMBB: |
| // ... |
| // TrueVal = ... |
| // cmpTY ccX, r1, r2 |
| // bCC copy1MBB |
| // fallthrough --> copy0MBB |
| MachineBasicBlock *copy0MBB = new MachineBasicBlock(LLVM_BB); |
| MachineBasicBlock *sinkMBB = new MachineBasicBlock(LLVM_BB); |
| BuildMI(BB, Opc, 2).addReg(CCReg).addMBB(sinkMBB); |
| MachineFunction *F = BB->getParent(); |
| F->getBasicBlockList().insert(It, copy0MBB); |
| F->getBasicBlockList().insert(It, sinkMBB); |
| // Update machine-CFG edges |
| BB->addSuccessor(copy0MBB); |
| BB->addSuccessor(sinkMBB); |
| |
| // copy0MBB: |
| // %FalseValue = ... |
| // # fallthrough to sinkMBB |
| BB = copy0MBB; |
| |
| // If the false value is simple enough, evaluate it here, to avoid it being |
| // evaluated on the true edge. |
| if (FalseValue == 0) |
| FalseValue = SelectExpr(N.getOperand(3)); |
| |
| // Update machine-CFG edges |
| BB->addSuccessor(sinkMBB); |
| |
| // sinkMBB: |
| // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] |
| // ... |
| BB = sinkMBB; |
| BuildMI(BB, PPC::PHI, 4, Result).addReg(FalseValue) |
| .addMBB(copy0MBB).addReg(TrueValue).addMBB(thisMBB); |
| return Result; |
| } |
| |
| case ISD::Constant: { |
| assert(N.getValueType() == MVT::i32 && |
| "Only i32 constants are legal on this target!"); |
| unsigned v = (unsigned)cast<ConstantSDNode>(N)->getValue(); |
| if (isInt16(v)) { |
| BuildMI(BB, PPC::LI, 1, Result).addSImm(Lo16(v)); |
| } else { |
| unsigned Hi = Hi16(v); |
| unsigned Lo = Lo16(v); |
| if (Lo) { |
| Tmp1 = MakeIntReg(); |
| BuildMI(BB, PPC::LIS, 1, Tmp1).addSImm(Hi); |
| BuildMI(BB, PPC::ORI, 2, Result).addReg(Tmp1).addImm(Lo); |
| } else { |
| BuildMI(BB, PPC::LIS, 1, Result).addSImm(Hi); |
| } |
| } |
| return Result; |
| } |
| |
| case ISD::FNEG: |
| if (!NoExcessFPPrecision && |
| ISD::FADD == N.getOperand(0).getOpcode() && |
| N.getOperand(0).Val->hasOneUse() && |
| ISD::FMUL == N.getOperand(0).getOperand(0).getOpcode() && |
| N.getOperand(0).getOperand(0).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(0).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(0).getOperand(1)); |
| Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| } else if (!NoExcessFPPrecision && |
| ISD::FADD == N.getOperand(0).getOpcode() && |
| N.getOperand(0).Val->hasOneUse() && |
| ISD::FMUL == N.getOperand(0).getOperand(1).getOpcode() && |
| N.getOperand(0).getOperand(1).Val->hasOneUse()) { |
| ++FusedFP; // Statistic |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(1).getOperand(0)); |
| Tmp2 = SelectExpr(N.getOperand(0).getOperand(1).getOperand(1)); |
| Tmp3 = SelectExpr(N.getOperand(0).getOperand(0)); |
| Opc = DestType == MVT::f64 ? PPC::FNMADD : PPC::FNMADDS; |
| BuildMI(BB, Opc, 3, Result).addReg(Tmp1).addReg(Tmp2).addReg(Tmp3); |
| } else if (ISD::FABS == N.getOperand(0).getOpcode()) { |
| Tmp1 = SelectExpr(N.getOperand(0).getOperand(0)); |
| if (N.getOperand(0).getValueType() == MVT::f32) |
| BuildMI(BB, PPC::FNABSS, 1, Result).addReg(Tmp1); |
| else |
| BuildMI(BB, PPC::FNABSD, 1, Result).addReg(Tmp1); |
| |
| } else { |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| if (N.getOperand(0).getValueType() == MVT::f32) |
| BuildMI(BB, PPC::FNEGS, 1, Result).addReg(Tmp1); |
| else |
| BuildMI(BB, PPC::FNEGD, 1, Result).addReg(Tmp1); |
| } |
| return Result; |
| |
| case ISD::FABS: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| if (N.getOperand(0).getValueType() == MVT::f32) |
| BuildMI(BB, PPC::FABSS, 1, Result).addReg(Tmp1); |
| else |
| BuildMI(BB, PPC::FABSD, 1, Result).addReg(Tmp1); |
| return Result; |
| |
| case ISD::FSQRT: |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| Opc = DestType == MVT::f64 ? PPC::FSQRT : PPC::FSQRTS; |
| BuildMI(BB, Opc, 1, Result).addReg(Tmp1); |
| return Result; |
| |
| case ISD::FP_ROUND: |
| assert (DestType == MVT::f32 && |
| N.getOperand(0).getValueType() == MVT::f64 && |
| "only f64 to f32 conversion supported here"); |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::FRSP, 1, Result).addReg(Tmp1); |
| return Result; |
| |
| case ISD::FP_EXTEND: |
| assert (DestType == MVT::f64 && |
| N.getOperand(0).getValueType() == MVT::f32 && |
| "only f32 to f64 conversion supported here"); |
| Tmp1 = SelectExpr(N.getOperand(0)); |
| BuildMI(BB, PPC::FMRSD, 1, Result).addReg(Tmp1); |
| return Result; |
| } |
| return 0; |
| } |
| |
| void ISel::Select(SDOperand N) { |
| unsigned Tmp1, Tmp2, Tmp3, Opc; |
| unsigned opcode = N.getOpcode(); |
| |
| if (!ExprMap.insert(std::make_pair(N, 1)).second) |
| return; // Already selected. |
| |
| SDNode *Node = N.Val; |
| |
| switch (Node->getOpcode()) { |
| default: |
| Node->dump(); std::cerr << "\n"; |
| assert(0 && "Node not handled yet!"); |
| case ISD::EntryToken: return; // Noop |
| case ISD::TokenFactor: |
| for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i) |
| Select(Node->getOperand(i)); |
| return; |
| case ISD::CALLSEQ_START: |
| case ISD::CALLSEQ_END: |
| Select(N.getOperand(0)); |
| Tmp1 = cast<ConstantSDNode>(N.getOperand(1))->getValue(); |
| Opc = N.getOpcode() == ISD::CALLSEQ_START ? PPC::ADJCALLSTACKDOWN : |
| PPC::ADJCALLSTACKUP; |
| BuildMI(BB, Opc, 1).addImm(Tmp1); |
| return; |
| case ISD::BR: { |
| MachineBasicBlock *Dest = |
| cast<BasicBlockSDNode>(N.getOperand(1))->getBasicBlock(); |
| Select(N.getOperand(0)); |
| BuildMI(BB, PPC::B, 1).addMBB(Dest); |
| return; |
| } |
| case ISD::BR_CC: |
| case ISD::BRTWOWAY_CC: |
| SelectBranchCC(N); |
| return; |
| case ISD::CopyToReg: |
| Select(N.getOperand(0)); |
| Tmp1 = SelectExpr(N.getOperand(2)); |
| Tmp2 = cast<RegisterSDNode>(N.getOperand(1))->getReg(); |
| |
| if (Tmp1 != Tmp2) { |
| if (N.getOperand(2).getValueType() == MVT::f64) |
| BuildMI(BB, PPC::FMRD, 1, Tmp2).addReg(Tmp1); |
| else if (N.getOperand(2).getValueType() == MVT::f32) |
| BuildMI(BB, PPC::FMRS, 1, Tmp2).addReg(Tmp1); |
| else |
| BuildMI(BB, PPC::OR4, 2, Tmp2).addReg(Tmp1).addReg(Tmp1); |
| } |
| return; |
| case ISD::ImplicitDef: |
| Select(N.getOperand(0)); |
| Tmp1 = cast<RegisterSDNode>(N.getOperand(1))->getReg(); |
| if (N.getOperand(1).getValueType() == MVT::i32) |
| BuildMI(BB, PPC::IMPLICIT_DEF_GPR, 0, Tmp1); |
| else if (N.getOperand(1).getValueType() == MVT::f32) |
| BuildMI(BB, PPC::IMPLICIT_DEF_F4, 0, Tmp1); |
| else |
| BuildMI(BB, PPC::IMPLICIT_DEF_F8, 0, Tmp1); |
| return; |
| case ISD::RET: |
| switch (N.getNumOperands()) { |
| default: |
| assert(0 && "Unknown return instruction!"); |
| case 3: |
| assert(N.getOperand(1).getValueType() == MVT::i32 && |
| N.getOperand(2).getValueType() == MVT::i32 && |
| "Unknown two-register value!"); |
| Select(N.getOperand(0)); |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| Tmp2 = SelectExpr(N.getOperand(2)); |
| BuildMI(BB, PPC::OR4, 2, PPC::R3).addReg(Tmp2).addReg(Tmp2); |
| BuildMI(BB, PPC::OR4, 2, PPC::R4).addReg(Tmp1).addReg(Tmp1); |
| break; |
| case 2: |
| Select(N.getOperand(0)); |
| Tmp1 = SelectExpr(N.getOperand(1)); |
| switch (N.getOperand(1).getValueType()) { |
| default: |
| assert(0 && "Unknown return type!"); |
| case MVT::f64: |
| BuildMI(BB, PPC::FMRD, 1, PPC::F1).addReg(Tmp1); |
| break; |
| case MVT::f32: |
| BuildMI(BB, PPC::FMRS, 1, PPC::F1).addReg(Tmp1); |
| break; |
| case MVT::i32: |
| BuildMI(BB, PPC::OR4, 2, PPC::R3).addReg(Tmp1).addReg(Tmp1); |
| break; |
| } |
| case 1: |
| Select(N.getOperand(0)); |
| break; |
| } |
| BuildMI(BB, PPC::BLR, 0); // Just emit a 'ret' instruction |
| return; |
| case ISD::TRUNCSTORE: |
| case ISD::STORE: { |
| SDOperand Chain = N.getOperand(0); |
| SDOperand Value = N.getOperand(1); |
| SDOperand Address = N.getOperand(2); |
| Select(Chain); |
| |
| Tmp1 = SelectExpr(Value); //value |
| |
| if (opcode == ISD::STORE) { |
| switch(Value.getValueType()) { |
| default: assert(0 && "unknown Type in store"); |
| case MVT::i32: Opc = PPC::STW; break; |
| case MVT::f64: Opc = PPC::STFD; break; |
| case MVT::f32: Opc = PPC::STFS; break; |
| } |
| } else { //ISD::TRUNCSTORE |
| switch(cast<VTSDNode>(Node->getOperand(4))->getVT()) { |
| default: assert(0 && "unknown Type in store"); |
| case MVT::i8: Opc = PPC::STB; break; |
| case MVT::i16: Opc = PPC::STH; break; |
| } |
| } |
| |
| if(Address.getOpcode() == ISD::FrameIndex) { |
| Tmp2 = cast<FrameIndexSDNode>(Address)->getIndex(); |
| addFrameReference(BuildMI(BB, Opc, 3).addReg(Tmp1), (int)Tmp2); |
| } else { |
| int offset; |
| switch(SelectAddr(Address, Tmp2, offset)) { |
| default: assert(0 && "Unhandled return value from SelectAddr"); |
| case 0: // imm offset, no frame, no index |
| BuildMI(BB, Opc, 3).addReg(Tmp1).addSImm(offset).addReg(Tmp2); |
| break; |
| case 1: // imm offset + frame index |
| addFrameReference(BuildMI(BB, Opc, 3).addReg(Tmp1), (int)Tmp2, offset); |
| break; |
| case 2: // base+index addressing |
| Opc = IndexedOpForOp(Opc); |
| BuildMI(BB, Opc, 3).addReg(Tmp1).addReg(Tmp2).addReg(offset); |
| break; |
| case 3: { |
| GlobalAddressSDNode *GN = cast<GlobalAddressSDNode>(Address); |
| GlobalValue *GV = GN->getGlobal(); |
| BuildMI(BB, Opc, 3).addReg(Tmp1).addGlobalAddress(GV).addReg(Tmp2); |
| } |
| } |
| } |
| return; |
| } |
| case ISD::EXTLOAD: |
| case ISD::SEXTLOAD: |
| case ISD::ZEXTLOAD: |
| case ISD::LOAD: |
| case ISD::CopyFromReg: |
| case ISD::TAILCALL: |
| case ISD::CALL: |
| case ISD::DYNAMIC_STACKALLOC: |
| ExprMap.erase(N); |
| SelectExpr(N); |
| return; |
| } |
| assert(0 && "Should not be reached!"); |
| } |
| |
| |
| /// createPPCPatternInstructionSelector - This pass converts an LLVM function |
| /// into a machine code representation using pattern matching and a machine |
| /// description file. |
| /// |
| FunctionPass *llvm::createPPCISelPattern(TargetMachine &TM) { |
| return new ISel(TM); |
| } |
| |