Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -100,10 +100,12 @@ bool selectRet(const Instruction *I); bool selectTrunc(const Instruction *I); bool selectIntExt(const Instruction *I); + bool selectShift(const Instruction *I); // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); bool isTypeSupported(Type *Ty, MVT &VT); + bool isValueAvailable(const Value *V) const; bool isLoadTypeLegal(Type *Ty, MVT &VT); bool computeAddress(const Value *Obj, Address &Addr); bool computeCallAddress(const Value *V, Address &Addr); @@ -478,6 +480,16 @@ return false; } +bool MipsFastISel::isValueAvailable(const Value *V) const { + if (!isa(V)) + return true; + + const auto *I = cast(V); + if (FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) + return true; + + return false; +} bool MipsFastISel::isLoadTypeLegal(Type *Ty, MVT &VT) { if (isTypeLegal(Ty, VT)) return true; @@ -1279,8 +1291,28 @@ if (!SrcReg) return false; - // Because the high bits are undefined, a truncate doesn't generate - // any code. + uint64_t Mask = 0; + MVT DVT = DestVT.getSimpleVT(); + switch (DVT.SimpleTy) { + default: + // Trunc i64 to i32 is handled by the target-independent fast-isel. + return false; + case MVT::i1: + Mask = 0x1; + break; + case MVT::i8: + Mask = 0xff; + break; + case MVT::i16: + Mask = 0xffff; + break; + } + if (Mask != 0) { + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::ANDi, DestReg).addReg(SrcReg).addImm(Mask); + SrcReg = DestReg; + } + updateValueMap(I, SrcReg); return true; } @@ -1386,6 +1418,74 @@ return Success ? DestReg : 0; } +bool MipsFastISel::selectShift(const Instruction *I) { + MVT RetVT; + if (!isTypeSupported(I->getType(), RetVT)) + return false; + unsigned ResultReg = createResultReg(&Mips::GPR32RegClass); + if (!ResultReg) + return false; + unsigned Opcode = I->getOpcode(); + const Value *Op0 = I->getOperand(0); + unsigned Op0Reg = getRegForValue(Op0); + if (!Op0Reg) + return false; + if (Opcode == Instruction::AShr) { + unsigned TempReg = createResultReg(&Mips::GPR32RegClass); + if (!TempReg) + return false; + MVT Op0MVT = TLI.getValueType(Op0->getType(), true).getSimpleVT(); + if (!emitIntSExt(Op0MVT, Op0Reg, MVT::i32, TempReg)) + return false; + Op0Reg = TempReg; + } + // if AShr then we need to make sure the operand0 is sign extended + // + if (const auto *C = dyn_cast(I->getOperand(1))) { + uint64_t ShiftVal = C->getZExtValue(); + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLL; + break; + case Instruction::AShr: + Opcode = Mips::SRA; + // this requires some extra work and so far + // it is never called. we need to sign extend Op0 before + // doing the shift if it is i8 or i16. + break; + case Instruction::LShr: + Opcode = Mips::SRL; + break; + } + emitInst(Opcode, ResultReg).addReg(Op0Reg).addImm(ShiftVal); + updateValueMap(I, ResultReg); + return true; + } + + unsigned Op1Reg = getRegForValue(I->getOperand(1)); + if (!Op1Reg) + return false; + + switch (Opcode) { + default: + llvm_unreachable("Unexpected instruction."); + case Instruction::Shl: + Opcode = Mips::SLLV; + break; + case Instruction::AShr: + Opcode = Mips::SRAV; + break; + case Instruction::LShr: + Opcode = Mips::SRLV; + break; + } + emitInst(Opcode, ResultReg).addReg(Op0Reg).addReg(Op1Reg); + updateValueMap(I, ResultReg); + return true; +} + bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -1396,6 +1496,10 @@ return selectLoad(I); case Instruction::Store: return selectStore(I); + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + return selectShift(I); case Instruction::And: case Instruction::Or: case Instruction::Xor: