Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -105,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. @@ -166,6 +166,12 @@ 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, @@ -318,10 +324,11 @@ return 0; } -bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr) { +bool MipsFastISel::computeAddress(const Value *Obj, Address &Addr, Type *Ty) { // // 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 @@ -329,26 +336,73 @@ if (FuncInfo.StaticAllocaMap.count(static_cast(Obj)) || FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) { Opcode = I->getOpcode(); + U = I; } } else if (isa(Obj)) return false; - if (isa(Obj)) { - switch (Opcode) { - default: - 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); + 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; - } - break; - } + // 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; } - return false; + break; + } } Addr.setReg(getRegForValue(Obj)); return Addr.getReg() != 0; @@ -556,13 +610,14 @@ return false; } 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 = 0; + unsigned Offset = Addr.getOffset(); MachineFrameInfo &MFI = *MF->getFrameInfo(); MachineMemOperand *MMO = MF->getMachineMemOperand( MachinePointerInfo::getFixedStack(FI), MachineMemOperand::MOLoad, @@ -606,13 +661,14 @@ return false; } 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 = 0; + unsigned Offset = Addr.getOffset();; MachineFrameInfo &MFI = *MF->getFrameInfo(); ; MachineMemOperand *MMO = MF->getMachineMemOperand( @@ -640,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; @@ -670,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())) @@ -1312,6 +1368,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) { 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-9]+]], 0($[[REG_RESULT]]) +; CHECK-LABEL: .end goo + ret void +} +