X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=lib%2FTarget%2FMSP430%2FMSP430ISelLowering.cpp;h=ef81f51229f5861e6bd89f72921fb110874366cf;hb=80c062001efbf1d3946d5cc4fcea7ad2d876ba64;hp=5012791d38032bd779b48fcdd6435495bcea7f92;hpb=6bfcba7e137113e5f38cc4f937ad61cc7253ec74;p=oota-llvm.git diff --git a/lib/Target/MSP430/MSP430ISelLowering.cpp b/lib/Target/MSP430/MSP430ISelLowering.cpp index 5012791d380..ef81f51229f 100644 --- a/lib/Target/MSP430/MSP430ISelLowering.cpp +++ b/lib/Target/MSP430/MSP430ISelLowering.cpp @@ -115,8 +115,8 @@ MSP430TargetLowering::MSP430TargetLowering(MSP430TargetMachine &tm) : setOperationAction(ISD::BR_CC, MVT::i8, Custom); setOperationAction(ISD::BR_CC, MVT::i16, Custom); setOperationAction(ISD::BRCOND, MVT::Other, Expand); - setOperationAction(ISD::SETCC, MVT::i8, Expand); - setOperationAction(ISD::SETCC, MVT::i16, Expand); + setOperationAction(ISD::SETCC, MVT::i8, Custom); + setOperationAction(ISD::SETCC, MVT::i16, Custom); setOperationAction(ISD::SELECT, MVT::i8, Expand); setOperationAction(ISD::SELECT, MVT::i16, Expand); setOperationAction(ISD::SELECT_CC, MVT::i8, Custom); @@ -183,6 +183,7 @@ SDValue MSP430TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) { case ISD::SRA: return LowerShifts(Op, DAG); case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG); case ISD::ExternalSymbol: return LowerExternalSymbol(Op, DAG); + case ISD::SETCC: return LowerSETCC(Op, DAG); case ISD::BR_CC: return LowerBR_CC(Op, DAG); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG); case ISD::SIGN_EXTEND: return LowerSIGN_EXTEND(Op, DAG); @@ -272,11 +273,13 @@ MSP430TargetLowering::LowerFormalArguments(SDValue Chain, SDValue MSP430TargetLowering::LowerCall(SDValue Chain, SDValue Callee, CallingConv::ID CallConv, bool isVarArg, - bool isTailCall, + bool &isTailCall, const SmallVectorImpl &Outs, const SmallVectorImpl &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) { + // MSP430 target does not yet support tail call optimization. + isTailCall = false; switch (CallConv) { default: @@ -591,9 +594,21 @@ SDValue MSP430TargetLowering::LowerShifts(SDValue Op, EVT VT = Op.getValueType(); DebugLoc dl = N->getDebugLoc(); - // We currently only lower shifts of constant argument. + // Expand non-constant shifts to loops: if (!isa(N->getOperand(1))) - return SDValue(); + switch (Opc) { + default: + assert(0 && "Invalid shift opcode!"); + case ISD::SHL: + return DAG.getNode(MSP430ISD::SHL, dl, + VT, N->getOperand(0), N->getOperand(1)); + case ISD::SRA: + return DAG.getNode(MSP430ISD::SRA, dl, + VT, N->getOperand(0), N->getOperand(1)); + case ISD::SRL: + return DAG.getNode(MSP430ISD::SRL, dl, + VT, N->getOperand(0), N->getOperand(1)); + } uint64_t ShiftAmount = cast(N->getOperand(1))->getZExtValue(); @@ -647,36 +662,68 @@ static SDValue EmitCMP(SDValue &LHS, SDValue &RHS, SDValue &TargetCC, default: llvm_unreachable("Invalid integer condition!"); case ISD::SETEQ: TCC = MSP430CC::COND_E; // aka COND_Z - // Minor optimization: if RHS is a constant, swap operands, then the + // Minor optimization: if LHS is a constant, swap operands, then the // constant can be folded into comparison. - if (RHS.getOpcode() == ISD::Constant) + if (LHS.getOpcode() == ISD::Constant) std::swap(LHS, RHS); break; case ISD::SETNE: TCC = MSP430CC::COND_NE; // aka COND_NZ - // Minor optimization: if RHS is a constant, swap operands, then the + // Minor optimization: if LHS is a constant, swap operands, then the // constant can be folded into comparison. - if (RHS.getOpcode() == ISD::Constant) + if (LHS.getOpcode() == ISD::Constant) std::swap(LHS, RHS); break; case ISD::SETULE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETUGE: + // Turn lhs u>= rhs with lhs constant into rhs u< lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_LO; + break; + } TCC = MSP430CC::COND_HS; // aka COND_C break; case ISD::SETUGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETULT: + // Turn lhs u< rhs with lhs constant into rhs u>= lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_HS; + break; + } TCC = MSP430CC::COND_LO; // aka COND_NC break; case ISD::SETLE: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETGE: + // Turn lhs >= rhs with lhs constant into rhs < lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_L; + break; + } TCC = MSP430CC::COND_GE; break; case ISD::SETGT: std::swap(LHS, RHS); // FALLTHROUGH case ISD::SETLT: + // Turn lhs < rhs with lhs constant into rhs >= lhs+1, this allows us to + // fold constant into instruction. + if (const ConstantSDNode * C = dyn_cast(LHS)) { + LHS = RHS; + RHS = DAG.getConstant(C->getSExtValue() + 1, C->getValueType(0)); + TCC = MSP430CC::COND_GE; + break; + } TCC = MSP430CC::COND_L; break; } @@ -701,6 +748,90 @@ SDValue MSP430TargetLowering::LowerBR_CC(SDValue Op, SelectionDAG &DAG) { Chain, Dest, TargetCC, Flag); } + +SDValue MSP430TargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) { + SDValue LHS = Op.getOperand(0); + SDValue RHS = Op.getOperand(1); + DebugLoc dl = Op.getDebugLoc(); + + // If we are doing an AND and testing against zero, then the CMP + // will not be generated. The AND (or BIT) will generate the condition codes, + // but they are different from CMP. + // FIXME: since we're doing a post-processing, use a pseudoinstr here, so + // lowering & isel wouldn't diverge. + bool andCC = false; + if (ConstantSDNode *RHSC = dyn_cast(RHS)) { + if (RHSC->isNullValue() && LHS.hasOneUse() && + (LHS.getOpcode() == ISD::AND || + (LHS.getOpcode() == ISD::TRUNCATE && + LHS.getOperand(0).getOpcode() == ISD::AND))) { + andCC = true; + } + } + ISD::CondCode CC = cast(Op.getOperand(2))->get(); + SDValue TargetCC; + SDValue Flag = EmitCMP(LHS, RHS, TargetCC, CC, dl, DAG); + + // Get the condition codes directly from the status register, if its easy. + // Otherwise a branch will be generated. Note that the AND and BIT + // instructions generate different flags than CMP, the carry bit can be used + // for NE/EQ. + bool Invert = false; + bool Shift = false; + bool Convert = true; + switch (cast(TargetCC)->getZExtValue()) { + default: + Convert = false; + break; + case MSP430CC::COND_HS: + // Res = SRW & 1, no processing is required + break; + case MSP430CC::COND_LO: + // Res = ~(SRW & 1) + Invert = true; + break; + case MSP430CC::COND_NE: + if (andCC) { + // C = ~Z, thus Res = SRW & 1, no processing is required + } else { + // Res = (SRW >> 1) & 1 + Shift = true; + } + break; + case MSP430CC::COND_E: + if (andCC) { + // C = ~Z, thus Res = ~(SRW & 1) + } else { + // Res = ~((SRW >> 1) & 1) + Shift = true; + } + Invert = true; + break; + } + EVT VT = Op.getValueType(); + SDValue One = DAG.getConstant(1, VT); + if (Convert) { + SDValue SR = DAG.getCopyFromReg(DAG.getEntryNode(), dl, MSP430::SRW, + MVT::i16, Flag); + if (Shift) + // FIXME: somewhere this is turned into a SRL, lower it MSP specific? + SR = DAG.getNode(ISD::SRA, dl, MVT::i16, SR, One); + SR = DAG.getNode(ISD::AND, dl, MVT::i16, SR, One); + if (Invert) + SR = DAG.getNode(ISD::XOR, dl, MVT::i16, SR, One); + return SR; + } else { + SDValue Zero = DAG.getConstant(0, VT); + SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Flag); + SmallVector Ops; + Ops.push_back(One); + Ops.push_back(Zero); + Ops.push_back(TargetCC); + Ops.push_back(Flag); + return DAG.getNode(MSP430ISD::SELECT_CC, dl, VTs, &Ops[0], Ops.size()); + } +} + SDValue MSP430TargetLowering::LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) { SDValue LHS = Op.getOperand(0); SDValue RHS = Op.getOperand(1); @@ -833,21 +964,167 @@ const char *MSP430TargetLowering::getTargetNodeName(unsigned Opcode) const { case MSP430ISD::BR_CC: return "MSP430ISD::BR_CC"; case MSP430ISD::CMP: return "MSP430ISD::CMP"; case MSP430ISD::SELECT_CC: return "MSP430ISD::SELECT_CC"; + case MSP430ISD::SHL: return "MSP430ISD::SHL"; + case MSP430ISD::SRA: return "MSP430ISD::SRA"; } } +bool MSP430TargetLowering::isTruncateFree(const Type *Ty1, + const Type *Ty2) const { + if (!Ty1->isInteger() || !Ty2->isInteger()) + return false; + + return (Ty1->getPrimitiveSizeInBits() > Ty2->getPrimitiveSizeInBits()); +} + +bool MSP430TargetLowering::isTruncateFree(EVT VT1, EVT VT2) const { + if (!VT1.isInteger() || !VT2.isInteger()) + return false; + + return (VT1.getSizeInBits() > VT2.getSizeInBits()); +} + +bool MSP430TargetLowering::isZExtFree(const Type *Ty1, const Type *Ty2) const { + // MSP430 implicitly zero-extends 8-bit results in 16-bit registers. + return 0 && Ty1->isInteger(8) && Ty2->isInteger(16); +} + +bool MSP430TargetLowering::isZExtFree(EVT VT1, EVT VT2) const { + // MSP430 implicitly zero-extends 8-bit results in 16-bit registers. + return 0 && VT1 == MVT::i8 && VT2 == MVT::i16; +} + //===----------------------------------------------------------------------===// // Other Lowering Code //===----------------------------------------------------------------------===// +MachineBasicBlock* +MSP430TargetLowering::EmitShiftInstr(MachineInstr *MI, + MachineBasicBlock *BB, + DenseMap *EM) const { + MachineFunction *F = BB->getParent(); + MachineRegisterInfo &RI = F->getRegInfo(); + DebugLoc dl = MI->getDebugLoc(); + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); + + unsigned Opc; + const TargetRegisterClass * RC; + switch (MI->getOpcode()) { + default: + assert(0 && "Invalid shift opcode!"); + case MSP430::Shl8: + Opc = MSP430::SHL8r1; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Shl16: + Opc = MSP430::SHL16r1; + RC = MSP430::GR16RegisterClass; + break; + case MSP430::Sra8: + Opc = MSP430::SAR8r1; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Sra16: + Opc = MSP430::SAR16r1; + RC = MSP430::GR16RegisterClass; + break; + case MSP430::Srl8: + Opc = MSP430::SAR8r1c; + RC = MSP430::GR8RegisterClass; + break; + case MSP430::Srl16: + Opc = MSP430::SAR16r1c; + RC = MSP430::GR16RegisterClass; + break; + } + + const BasicBlock *LLVM_BB = BB->getBasicBlock(); + MachineFunction::iterator I = BB; + ++I; + + // Create loop block + MachineBasicBlock *LoopBB = F->CreateMachineBasicBlock(LLVM_BB); + MachineBasicBlock *RemBB = F->CreateMachineBasicBlock(LLVM_BB); + + F->insert(I, LoopBB); + F->insert(I, RemBB); + + // Update machine-CFG edges by transferring all successors of the current + // block to the block containing instructions after shift. + RemBB->transferSuccessors(BB); + + // Inform sdisel of the edge changes. + for (MachineBasicBlock::succ_iterator SI = BB->succ_begin(), + SE = BB->succ_end(); SI != SE; ++SI) + EM->insert(std::make_pair(*SI, RemBB)); + + // Add adges BB => LoopBB => RemBB, BB => RemBB, LoopBB => LoopBB + BB->addSuccessor(LoopBB); + BB->addSuccessor(RemBB); + LoopBB->addSuccessor(RemBB); + LoopBB->addSuccessor(LoopBB); + + unsigned ShiftAmtReg = RI.createVirtualRegister(MSP430::GR8RegisterClass); + unsigned ShiftAmtReg2 = RI.createVirtualRegister(MSP430::GR8RegisterClass); + unsigned ShiftReg = RI.createVirtualRegister(RC); + unsigned ShiftReg2 = RI.createVirtualRegister(RC); + unsigned ShiftAmtSrcReg = MI->getOperand(2).getReg(); + unsigned SrcReg = MI->getOperand(1).getReg(); + unsigned DstReg = MI->getOperand(0).getReg(); + + // BB: + // cmp 0, N + // je RemBB + BuildMI(BB, dl, TII.get(MSP430::CMP8ri)) + .addReg(ShiftAmtSrcReg).addImm(0); + BuildMI(BB, dl, TII.get(MSP430::JCC)) + .addMBB(RemBB) + .addImm(MSP430CC::COND_E); + + // LoopBB: + // ShiftReg = phi [%SrcReg, BB], [%ShiftReg2, LoopBB] + // ShiftAmt = phi [%N, BB], [%ShiftAmt2, LoopBB] + // ShiftReg2 = shift ShiftReg + // ShiftAmt2 = ShiftAmt - 1; + BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftReg) + .addReg(SrcReg).addMBB(BB) + .addReg(ShiftReg2).addMBB(LoopBB); + BuildMI(LoopBB, dl, TII.get(MSP430::PHI), ShiftAmtReg) + .addReg(ShiftAmtSrcReg).addMBB(BB) + .addReg(ShiftAmtReg2).addMBB(LoopBB); + BuildMI(LoopBB, dl, TII.get(Opc), ShiftReg2) + .addReg(ShiftReg); + BuildMI(LoopBB, dl, TII.get(MSP430::SUB8ri), ShiftAmtReg2) + .addReg(ShiftAmtReg).addImm(1); + BuildMI(LoopBB, dl, TII.get(MSP430::JCC)) + .addMBB(LoopBB) + .addImm(MSP430CC::COND_NE); + + // RemBB: + // DestReg = phi [%SrcReg, BB], [%ShiftReg, LoopBB] + BuildMI(RemBB, dl, TII.get(MSP430::PHI), DstReg) + .addReg(SrcReg).addMBB(BB) + .addReg(ShiftReg2).addMBB(LoopBB); + + F->DeleteMachineInstr(MI); // The pseudo instruction is gone now. + return RemBB; +} + MachineBasicBlock* MSP430TargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *BB, DenseMap *EM) const { + unsigned Opc = MI->getOpcode(); + + if (Opc == MSP430::Shl8 || Opc == MSP430::Shl16 || + Opc == MSP430::Sra8 || Opc == MSP430::Sra16 || + Opc == MSP430::Srl8 || Opc == MSP430::Srl16) + return EmitShiftInstr(MI, BB, EM); + const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo(); DebugLoc dl = MI->getDebugLoc(); - assert((MI->getOpcode() == MSP430::Select16 || - MI->getOpcode() == MSP430::Select8) && + + assert((Opc == MSP430::Select16 || Opc == MSP430::Select8) && "Unexpected instr type to insert"); // To "insert" a SELECT instruction, we actually have to insert the diamond