Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -2,9 +2,12 @@ //---------------------===// #include "MipsCCState.h" +#include "MipsInstrInfo.h" +#include "MipsRegisterInfo.h" #include "MipsISelLowering.h" #include "MipsMachineFunction.h" #include "MipsRegisterInfo.h" +#include "MipsSEInstrInfo.h" #include "MipsSubtarget.h" #include "MipsTargetMachine.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -44,6 +47,7 @@ void setKind(BaseKind K) { Kind = K; } BaseKind getKind() const { return Kind; } bool isRegBase() const { return Kind == RegBase; } + bool isFIBase() const { return Kind == FrameIndexBase; } void setReg(unsigned Reg) { assert(isRegBase() && "Invalid base register access!"); Base.Reg = Reg; @@ -52,6 +56,14 @@ assert(isRegBase() && "Invalid base register access!"); return Base.Reg; } + void setFI(unsigned FI) { + assert(isFIBase() && "Invalid base frame index access!"); + Base.FI = FI; + } + unsigned getFI() const { + assert(isFIBase() && "Invalid base frame index access!"); + return Base.FI; + } void setOffset(int64_t Offset_) { Offset = Offset_; } int64_t getOffset() const { return Offset; } void setGlobalValue(const GlobalValue *G) { GV = G; } @@ -60,10 +72,11 @@ /// Subtarget - Keep a pointer to the MipsSubtarget around so that we can /// make the right decision when generating code for different targets. + Module &M; const TargetMachine &TM; - const MipsSubtarget *Subtarget; const TargetInstrInfo &TII; const TargetLowering &TLI; + const MipsSubtarget *Subtarget; MipsFunctionInfo *MFI; // Convenience variables to avoid some queries. @@ -92,7 +105,7 @@ // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); bool isLoadTypeLegal(Type *Ty, MVT &VT); - bool computeAddress(const Value *Obj, Address &Addr); + bool computeAddress(const Value *Obj, Address &Addr, Type *Ty = nullptr); bool computeCallAddress(const Value *V, Address &Addr); // Emit helper routines. @@ -153,20 +166,27 @@ unsigned &NumBytes); bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes); +private: + // if the offset does not fit then materialize it in a register first. + // + void ensureOffset(Address &Addr, bool FitsOffset); + + public: // Backend specific FastISel code. explicit MipsFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) - : FastISel(funcInfo, libInfo), TM(funcInfo.MF->getTarget()), - Subtarget( - &static_cast(funcInfo.MF->getSubtarget())), - TII(*Subtarget->getInstrInfo()), TLI(*Subtarget->getTargetLowering()) { + : FastISel(funcInfo, libInfo), + M(const_cast(*funcInfo.Fn->getParent())), + TM(funcInfo.MF->getTarget()), + TII(*TM.getSubtargetImpl()->getInstrInfo()), + TLI(*TM.getSubtargetImpl()->getTargetLowering()), + Subtarget(&TM.getSubtarget()) { MFI = funcInfo.MF->getInfo(); Context = &funcInfo.Fn->getContext(); - TargetSupported = - ((TM.getRelocationModel() == Reloc::PIC_) && - ((Subtarget->hasMips32r2() || Subtarget->hasMips32()) && - (static_cast(TM).getABI().IsO32()))); + TargetSupported = ((Subtarget->getRelocationModel() == Reloc::PIC_) && + ((Subtarget->hasMips32r2() || Subtarget->hasMips32()) && + (Subtarget->isABI_O32()))); UnsupportedFPMode = Subtarget->isFP64bit(); } @@ -187,9 +207,9 @@ llvm_unreachable("should not be called"); } -static bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT, - CCValAssign::LocInfo LocInfo, - ISD::ArgFlagsTy ArgFlags, CCState &State) { +bool CC_MipsO32_FP64(unsigned ValNo, MVT ValVT, MVT LocVT, + CCValAssign::LocInfo LocInfo, ISD::ArgFlagsTy ArgFlags, + CCState &State) { llvm_unreachable("should not be called"); } @@ -304,15 +324,86 @@ return 0; } -bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { - // This construct looks a big awkward but it is how other ports handle this - // and as this function is more fully completed, these cases which - // return false will have additional code in them. +bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty) { // - if (isa(Obj)) - return false; - else if (isa(Obj)) + // This code is mostly cloned from AARch64 (which cloned it from earlier + // ports) + const User *U = nullptr; + unsigned Opcode = Instruction::UserOp1; + if (const Instruction *I = dyn_cast(Obj)) { + // Don't walk into other basic blocks unless the object is an alloca from + // another block, otherwise it may not have a virtual register assigned. + if (FuncInfo.StaticAllocaMap.count(static_cast(Obj)) || + FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { + Opcode = I->getOpcode(); + U = I; + } + } else if (isa(Obj)) return false; + switch (Opcode) { + default: + break; + case Instruction::BitCast: { + // Look through bitcasts. + return computeAddress(U->getOperand(0), Addr, Ty); + } + case Instruction::GetElementPtr: { + Address SavedAddr = Addr; + uint64_t TmpOffset = Addr.getOffset(); + // Iterate through the GEP folding the constants into offsets where + // we can. + gep_type_iterator GTI = gep_type_begin(U); + for (User::const_op_iterator i = U->op_begin() + 1, e = U->op_end(); i != e; + ++i, ++GTI) { + const Value *Op = *i; + if (StructType *STy = dyn_cast(*GTI)) { + const StructLayout *SL = DL.getStructLayout(STy); + unsigned Idx = cast(Op)->getZExtValue(); + TmpOffset += SL->getElementOffset(Idx); + } else { + uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType()); + for (;;) { + if (const ConstantInt *CI = dyn_cast(Op)) { + // Constant-offset addressing. + TmpOffset += CI->getSExtValue() * S; + break; + } + if (canFoldAddIntoGEP(U, Op)) { + // A compatible add with a constant operand. Fold the constant. + ConstantInt *CI = + cast(cast(Op)->getOperand(1)); + TmpOffset += CI->getSExtValue() * S; + // Iterate on the other operand. + Op = cast(Op)->getOperand(0); + continue; + } + // Unsupported + goto unsupported_gep; + } + } + } + + // Try to grab the base operand now. + Addr.setOffset(TmpOffset); + if (computeAddress(U->getOperand(0), Addr, Ty)) + return true; + // We failed, restore everything and try the other options. + Addr = SavedAddr; + unsupported_gep: + break; + } + case Instruction::Alloca: { + const AllocaInst *AI = cast(Obj); + DenseMap::iterator SI = + FuncInfo.StaticAllocaMap.find(AI); + if (SI != FuncInfo.StaticAllocaMap.end()) { + Addr.setKind(Address::FrameIndexBase); + Addr.setFI(SI->second); + return true; + } + break; + } + } Addr.setReg(getRegForValue(Obj)); return Addr.getReg() != 0; } @@ -518,8 +609,26 @@ default: return false; } - emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); - return true; + if (Addr.isRegBase()) { + ensureOffset(Addr, isInt<16>(Addr.getOffset())); + emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); + return true; + } + if (Addr.isFIBase()) { + unsigned FI = Addr.getFI(); + unsigned Align = 4; + unsigned Offset = Addr.getOffset(); + MachineFrameInfo &MFI = *MF->getFrameInfo(); + MachineMemOperand *MMO = MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), Align); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), ResultReg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + return true; + } + return false; } bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr, @@ -551,8 +660,28 @@ default: return false; } - emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); - return true; + if (Addr.isRegBase()) { + ensureOffset(Addr, isInt<16>(Addr.getOffset())); + emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); + return true; + } + if (Addr.isFIBase()) { + unsigned FI = Addr.getFI(); + unsigned Align = 4; + unsigned Offset = Addr.getOffset();; + MachineFrameInfo &MFI = *MF->getFrameInfo(); + ; + MachineMemOperand *MMO = MF->getMachineMemOperand( + MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOLoad, + MFI.getObjectSize(FI), Align); + BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc)) + .addReg(SrcReg) + .addFrameIndex(FI) + .addImm(Offset) + .addMemOperand(MMO); + return true; + } + return false; } bool MipsFastISel::selectLoad(const Instruction *I) { @@ -567,7 +696,7 @@ // See if we can handle this address. Address Addr; - if (!computeAddress(I->getOperand(0), Addr)) + if (!computeAddress(I->getOperand(0), Addr, I->getType())) return false; unsigned ResultReg; @@ -597,7 +726,7 @@ // See if we can handle this address. Address Addr; - if (!computeAddress(I->getOperand(1), Addr)) + if (!computeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType())) return false; if (!emitStore(VT, SrcReg, Addr, cast(I)->getAlignment())) @@ -971,15 +1100,6 @@ CLI.Call = MIB; - // Add implicit physical register uses to the call. - for (auto Reg : CLI.OutRegs) - MIB.addReg(Reg, RegState::Implicit); - - // Add a register mask with the call-preserved registers. Proper - // defs for return values will be added by setPhysRegsDeadExcept(). - MIB.addRegMask(TRI.getCallPreservedMask(CC)); - - CLI.Call = MIB; // Finish off the call including any return values. return finishCall(CLI, RetVT, NumBytes); } @@ -1244,6 +1364,17 @@ return VReg; } +void MipsFastISel::ensureOffset(Address &Addr, bool FitsOffset) { + if (FitsOffset) + return; + unsigned TempReg = materialize32BitInt(Addr.getOffset(), &Mips::GPR32RegClass); + unsigned DestReg = createResultReg(&Mips::GPR32RegClass); + emitInst(Mips::ADDu, DestReg).addReg(TempReg).addReg(Addr.getReg()); + Addr.setReg(DestReg); + Addr.setOffset(0); + return; +} + namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) {