Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -2,9 +2,11 @@ //---------------------===// #include "MipsCCState.h" +#include "MipsInstrInfo.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 +46,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 +55,15 @@ 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; } @@ -92,7 +104,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,6 +165,10 @@ unsigned &NumBytes); bool finishCall(CallLoweringInfo &CLI, MVT RetVT, unsigned NumBytes); +private: + // If the offset does not fit then materialize it in a register first. + Address ensureOffsetFits(Address Addr, bool FitsOffset); + public: // Backend specific FastISel code. explicit MipsFastISel(FunctionLoweringInfo &funcInfo, @@ -303,15 +319,83 @@ 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. - // - if (isa(Obj)) - return false; - else if (isa(Obj)) +bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty) { + + 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; } @@ -517,8 +601,26 @@ default: return false; } - emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset()); - return true; + if (Addr.isRegBase()) { + Addr = ensureOffsetFits(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, @@ -550,8 +652,27 @@ default: return false; } - emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset()); - return true; + if (Addr.isRegBase()) { + Addr = ensureOffsetFits(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) { @@ -566,7 +687,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; @@ -970,15 +1091,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); } @@ -1243,6 +1355,19 @@ return VReg; } +MipsFastISel::Address MipsFastISel::ensureOffsetFits(Address Addr, + bool FitsOffset) { + if (!FitsOffset) { + 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 Addr; +} + namespace llvm { FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo, const TargetLibraryInfo *libInfo) { Index: test/CodeGen/Mips/Fast-ISel/overflt.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/overflt.ll @@ -0,0 +1,49 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | FileCheck %s +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel-abort -mcpu=mips32 \ +; RUN: < %s | FileCheck %s + +@x = common global [128000 x float] zeroinitializer, align 4 +@y = global float* getelementptr inbounds ([128000 x float]* @x, i32 0, i32 0), align 4 +@result = common global float 0.000000e+00, align 4 +@.str = private unnamed_addr constant [5 x i8] c"%f \0A\00", align 1 + +; Function Attrs: nounwind +define void @foo() { +entry: +; CHECK-LABEL: .ent foo + %0 = load float** @y, align 4 + %arrayidx = getelementptr inbounds float* %0, i32 64000 + store float 5.500000e+00, float* %arrayidx, align 4 +; CHECK: lui $[[REG_FPCONST_INT:[0-9]+]], 16560 +; CHECK: mtc1 $[[REG_FPCONST_INT]], $f[[REG_FPCONST:[0-9]+]] +; CHECK: lw $[[REG_Y_GOT:[0-9]+]], %got(y)(${{[0-9]+}}) +; CHECK: lw $[[REG_Y:[0-9]+]], 0($[[REG_Y_GOT]]) +; CHECK: lui $[[REG_IDX_UPPER:[0-9]+]], 3 +; CHECK: ori $[[REG_IDX:[0-9]+]], $[[REG_IDX_UPPER]], 59392 +; CHECK: addu $[[REG_Y_IDX:[0-9]+]], $[[REG_IDX]], $[[REG_Y]] +; CHECK: swc1 $f[[REG_FPCONST]], 0($[[REG_Y_IDX]]) + ret void +; CHECK-LABEL: .end foo +} + +; Function Attrs: nounwind +define void @goo() { +entry: +; CHECK-LABEL: .ent goo + %0 = load float** @y, align 4 + %arrayidx = getelementptr inbounds float* %0, i32 64000 + %1 = load float* %arrayidx, align 4 + store float %1, float* @result, align 4 +; CHECK-DAG: lw $[[REG_RESULT:[0-9]+]], %got(result)(${{[0-9]+}}) +; CHECK-DAG: lw $[[REG_Y_GOT:[0-9]+]], %got(y)(${{[0-9]+}}) +; CHECK-DAG: lw $[[REG_Y:[0-9]+]], 0($[[REG_Y_GOT]]) +; CHECK-DAG: lui $[[REG_IDX_UPPER:[0-9]+]], 3 +; CHECK-DAG: ori $[[REG_IDX:[0-9]+]], $[[REG_IDX_UPPER]], 59392 +; CHECK-DAG: addu $[[REG_Y_IDX:[0-9]+]], $[[REG_IDX]], $[[REG_Y]] +; CHECK-DAG: lwc1 $f[[Y_IDX:[0-9]+]], 0($[[REG_Y_IDX]]) +; CHECK-DAG: swc1 $f[[Y_IDX]], 0($[[REG_RESULT]]) +; CHECK-LABEL: .end goo + ret void +} +