Skip to content

Commit

Permalink
Beginning of alloca implementation for Mips fast-isel
Browse files Browse the repository at this point in the history
Summary: Begin to add various address modes; including alloca.

Test Plan: Make sure there are no regressions in test-suite at O0/02 in mips32r1/r2

Reviewers: dsanders

Reviewed By: dsanders

Subscribers: echristo, rfuhler, llvm-commits

Differential Revision: http://reviews.llvm.org/D6426

llvm-svn: 230300
  • Loading branch information
Reed Kotler committed Feb 24, 2015
1 parent 4ae3dda commit 5fb7d8b
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 20 deletions.
159 changes: 139 additions & 20 deletions llvm/lib/Target/Mips/MipsFastISel.cpp
Expand Up @@ -2,6 +2,7 @@
//---------------------===//

#include "MipsCCState.h"
#include "MipsInstrInfo.h"
#include "MipsISelLowering.h"
#include "MipsMachineFunction.h"
#include "MipsRegisterInfo.h"
Expand Down Expand Up @@ -44,6 +45,7 @@ class MipsFastISel final : public FastISel {
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;
Expand All @@ -52,6 +54,15 @@ class MipsFastISel final : public FastISel {
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; }
Expand Down Expand Up @@ -94,6 +105,7 @@ class MipsFastISel final : public FastISel {
bool isLoadTypeLegal(Type *Ty, MVT &VT);
bool computeAddress(const Value *Obj, Address &Addr);
bool computeCallAddress(const Value *V, Address &Addr);
void simplifyAddress(Address &Addr);

// Emit helper routines.
bool emitCmp(unsigned DestReg, const CmpInst *CI);
Expand Down Expand Up @@ -304,14 +316,82 @@ unsigned MipsFastISel::fastMaterializeConstant(const Constant *C) {
}

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<Instruction>(Obj))
return false;
else if (isa<ConstantExpr>(Obj))

const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
if (const Instruction *I = dyn_cast<Instruction>(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<const AllocaInst *>(Obj)) ||
FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB) {
Opcode = I->getOpcode();
U = I;
}
} else if (isa<ConstantExpr>(Obj))
return false;
switch (Opcode) {
default:
break;
case Instruction::BitCast: {
// Look through bitcasts.
return computeAddress(U->getOperand(0), Addr);
}
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<StructType>(*GTI)) {
const StructLayout *SL = DL.getStructLayout(STy);
unsigned Idx = cast<ConstantInt>(Op)->getZExtValue();
TmpOffset += SL->getElementOffset(Idx);
} else {
uint64_t S = DL.getTypeAllocSize(GTI.getIndexedType());
for (;;) {
if (const ConstantInt *CI = dyn_cast<ConstantInt>(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<ConstantInt>(cast<AddOperator>(Op)->getOperand(1));
TmpOffset += CI->getSExtValue() * S;
// Iterate on the other operand.
Op = cast<AddOperator>(Op)->getOperand(0);
continue;
}
// Unsupported
goto unsupported_gep;
}
}
}
// Try to grab the base operand now.
Addr.setOffset(TmpOffset);
if (computeAddress(U->getOperand(0), Addr))
return true;
// We failed, restore everything and try the other options.
Addr = SavedAddr;
unsupported_gep:
break;
}
case Instruction::Alloca: {
const AllocaInst *AI = cast<AllocaInst>(Obj);
DenseMap<const AllocaInst *, int>::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;
}
Expand Down Expand Up @@ -517,8 +597,26 @@ bool MipsFastISel::emitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
default:
return false;
}
emitInstLoad(Opc, ResultReg, Addr.getReg(), Addr.getOffset());
return true;
if (Addr.isRegBase()) {
simplifyAddress(Addr);
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,
Expand Down Expand Up @@ -550,8 +648,27 @@ bool MipsFastISel::emitStore(MVT VT, unsigned SrcReg, Address &Addr,
default:
return false;
}
emitInstStore(Opc, SrcReg, Addr.getReg(), Addr.getOffset());
return true;
if (Addr.isRegBase()) {
simplifyAddress(Addr);
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) {
Expand Down Expand Up @@ -970,15 +1087,6 @@ bool MipsFastISel::fastLowerCall(CallLoweringInfo &CLI) {

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);
}
Expand Down Expand Up @@ -1243,6 +1351,17 @@ unsigned MipsFastISel::getRegEnsuringSimpleIntegerWidening(const Value *V,
return VReg;
}

void MipsFastISel::simplifyAddress(Address &Addr) {
if (!isInt<16>(Addr.getOffset())) {
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);
}
}

namespace llvm {
FastISel *Mips::createFastISel(FunctionLoweringInfo &funcInfo,
const TargetLibraryInfo *libInfo) {
Expand Down
64 changes: 64 additions & 0 deletions llvm/test/CodeGen/Mips/Fast-ISel/overflt.ll
@@ -0,0 +1,64 @@
; 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
}

;
; Original C code for test.
;
;float x[128000];
;float *y = x;
;float result;


;void foo() {
; y[64000] = 5.5;
;}

;void goo() {
; result = y[64000];
;}

0 comments on commit 5fb7d8b

Please sign in to comment.