Skip to content

Commit

Permalink
[mips][mips16] Fix machine verifier errors about incorrect register c…
Browse files Browse the repository at this point in the history
…lasses on load/stores.

Summary:
[ls][bh] and [ls][bh]u cannot use sp-relative addresses and must therefore
lower frameindex nodes such that there is a copy to a CPU16Regs register. This
is now done consistently using a separate addressing mode that does not
permit frameindex nodes.

As part of this I've had to remove an optimization that reduced the number of
instructions needed to work around the lack of sp-relative addresses on [ls][bh]
and [ls][bh]u. This optimization used one of the eight CPU16Regs registers as
a copy of the stack pointer and it's implementation was the root cause of many
of the register vs register class mismatches.

lw/sw can use sp-relative addresses but we ought to ensure that we use the
correct version of lw/sw internally for things like IAS. This is not currently
the case and this change does not fix this. However, this change does clean it
up sufficiently well to fix the machine verifier failures.

Also removed irrelevant functions from stchar.ll.

Reviewers: sdardis

Subscribers: dsanders, sdardis, llvm-commits

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

llvm-svn: 272882
  • Loading branch information
dsandersllvm committed Jun 16, 2016
1 parent fa4d90d commit de7816b
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 227 deletions.
118 changes: 27 additions & 91 deletions llvm/lib/Target/Mips/Mips16ISelDAGToDAG.cpp
Expand Up @@ -91,88 +91,22 @@ void Mips16DAGToDAGISel::initGlobalBaseReg(MachineFunction &MF) {
.addReg(V2);
}

// Insert instructions to initialize the Mips16 SP Alias register in the
// first MBB of the function.
//
void Mips16DAGToDAGISel::initMips16SPAliasReg(MachineFunction &MF) {
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();

if (!MipsFI->mips16SPAliasRegSet())
return;

MachineBasicBlock &MBB = MF.front();
MachineBasicBlock::iterator I = MBB.begin();
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();
unsigned Mips16SPAliasReg = MipsFI->getMips16SPAliasReg();

BuildMI(MBB, I, DL, TII.get(Mips::MoveR3216), Mips16SPAliasReg)
.addReg(Mips::SP);
}

void Mips16DAGToDAGISel::processFunctionAfterISel(MachineFunction &MF) {
initGlobalBaseReg(MF);
initMips16SPAliasReg(MF);
}

/// getMips16SPAliasReg - Output the instructions required to put the
/// SP into a Mips16 accessible aliased register.
SDValue Mips16DAGToDAGISel::getMips16SPAliasReg() {
unsigned Mips16SPAliasReg =
MF->getInfo<MipsFunctionInfo>()->getMips16SPAliasReg();
auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
return CurDAG->getRegister(Mips16SPAliasReg, PtrVT);
}

void Mips16DAGToDAGISel::getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg) {
auto PtrVT = getTargetLowering()->getPointerTy(CurDAG->getDataLayout());
SDValue AliasFPReg = CurDAG->getRegister(Mips::S0, PtrVT);
if (Parent) {
switch (Parent->getOpcode()) {
case ISD::LOAD: {
LoadSDNode *SD = dyn_cast<LoadSDNode>(Parent);
switch (SD->getMemoryVT().getSizeInBits()) {
case 8:
case 16:
AliasReg = Subtarget->getFrameLowering()->hasFP(*MF)
? AliasFPReg
: getMips16SPAliasReg();
return;
}
break;
}
case ISD::STORE: {
StoreSDNode *SD = dyn_cast<StoreSDNode>(Parent);
switch (SD->getMemoryVT().getSizeInBits()) {
case 8:
case 16:
AliasReg = Subtarget->getFrameLowering()->hasFP(*MF)
? AliasFPReg
: getMips16SPAliasReg();
return;
}
break;
}
}
}
AliasReg = CurDAG->getRegister(Mips::SP, PtrVT);
return;
}

bool Mips16DAGToDAGISel::selectAddr16(SDNode *Parent, SDValue Addr,
SDValue &Base, SDValue &Offset,
SDValue &Alias) {
bool Mips16DAGToDAGISel::selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base,
SDValue &Offset) {
SDLoc DL(Addr);
EVT ValTy = Addr.getValueType();

Alias = CurDAG->getTargetConstant(0, DL, ValTy);

// if Address is FI, get the TargetFrameIndex.
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
Offset = CurDAG->getTargetConstant(0, DL, ValTy);
getMips16SPRefReg(Parent, Alias);
return true;
if (SPAllowed) {
if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
Offset = CurDAG->getTargetConstant(0, DL, ValTy);
return true;
}
}
// on PIC code Load GA
if (Addr.getOpcode() == MipsISD::Wrapper) {
Expand All @@ -189,15 +123,17 @@ bool Mips16DAGToDAGISel::selectAddr16(SDNode *Parent, SDValue Addr,
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
if (isInt<16>(CN->getSExtValue())) {

// If the first operand is a FI, get the TargetFI Node
if (FrameIndexSDNode *FIN =
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
getMips16SPRefReg(Parent, Alias);
} else
Base = Addr.getOperand(0);
if (SPAllowed) {
if (FrameIndexSDNode *FIN =
dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), ValTy);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy);
return true;
}
}

Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), DL, ValTy);
return true;
}
Expand All @@ -222,22 +158,22 @@ bool Mips16DAGToDAGISel::selectAddr16(SDNode *Parent, SDValue Addr,
return true;
}
}

// If an indexed floating point load/store can be emitted, return false.
const LSBaseSDNode *LS = dyn_cast<LSBaseSDNode>(Parent);

if (LS) {
if (LS->getMemoryVT() == MVT::f32 && Subtarget->hasMips4_32r2())
return false;
if (LS->getMemoryVT() == MVT::f64 && Subtarget->hasMips4_32r2())
return false;
}
}
Base = Addr;
Offset = CurDAG->getTargetConstant(0, DL, ValTy);
return true;
}

bool Mips16DAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base,
SDValue &Offset) {
return selectAddr(false, Addr, Base, Offset);
}

bool Mips16DAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base,
SDValue &Offset) {
return selectAddr(true, Addr, Base, Offset);
}

/// Select instructions not customized! Used for
/// expanded, promoted and normal instructions
bool Mips16DAGToDAGISel::trySelect(SDNode *Node) {
Expand Down
12 changes: 6 additions & 6 deletions llvm/lib/Target/Mips/Mips16ISelDAGToDAG.h
Expand Up @@ -27,14 +27,14 @@ class Mips16DAGToDAGISel : public MipsDAGToDAGISel {
const SDLoc &DL, EVT Ty, bool HasLo,
bool HasHi);

SDValue getMips16SPAliasReg();

bool runOnMachineFunction(MachineFunction &MF) override;

void getMips16SPRefReg(SDNode *Parent, SDValue &AliasReg);

bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base, SDValue &Offset,
SDValue &Alias) override;
bool selectAddr(bool SPAllowed, SDValue Addr, SDValue &Base,
SDValue &Offset);
bool selectAddr16(SDValue Addr, SDValue &Base,
SDValue &Offset) override;
bool selectAddr16SP(SDValue Addr, SDValue &Base,
SDValue &Offset) override;

bool trySelect(SDNode *Node) override;

Expand Down
69 changes: 31 additions & 38 deletions llvm/lib/Target/Mips/Mips16InstrInfo.td
Expand Up @@ -14,14 +14,26 @@
//
// Mips Address
//
def addr16 :
ComplexPattern<iPTR, 3, "selectAddr16", [frameindex], [SDNPWantParent]>;
def addr16 : ComplexPattern<iPTR, 2, "selectAddr16", [frameindex]>;
def addr16sp : ComplexPattern<iPTR, 2, "selectAddr16SP", [frameindex]>;

//
// Address operand
def mem16 : Operand<i32> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops CPU16Regs, simm16, CPU16RegsPlusSP);
let MIOperandInfo = (ops CPU16Regs, simm16);
let EncoderMethod = "getMemEncoding";
}

def mem16sp : Operand<i32> {
let PrintMethod = "printMemOperand";
// This should be CPUSPReg but the MIPS16 subtarget isn't good enough at
// keeping the sp-relative load and the other varieties separate at the
// moment. This lie fixes the problem sufficiently well to fix the errors
// emitted by -verify-machineinstrs and the output ends up correct as long
// as we use an external assembler (which is already a requirement for MIPS16
// for several other reasons).
let MIOperandInfo = (ops CPU16RegsPlusSP, simm16);
let EncoderMethod = "getMemEncoding";
}

Expand Down Expand Up @@ -215,19 +227,6 @@ class FEXT_2RI16_ins<bits<5> _op, string asmstr,
let Constraints = "$rx_ = $rx";
}


// this has an explicit sp argument that we ignore to work around a problem
// in the compiler
class FEXT_RI16_SP_explicit_ins<bits<5> _op, string asmstr,
InstrItinClass itin>:
FEXT_RI16<_op, (outs CPU16Regs:$rx), (ins CPUSPReg:$ry, simm16:$imm),
!strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>;

class FEXT_RI16_SP_Store_explicit_ins<bits<5> _op, string asmstr,
InstrItinClass itin>:
FEXT_RI16<_op, (outs), (ins CPU16Regs:$rx, CPUSPReg:$ry, simm16:$imm),
!strconcat(asmstr, "\t$rx, $imm ( $ry ); "), [], itin>;

//
// EXT-RRI instruction format
//
Expand Down Expand Up @@ -851,9 +850,7 @@ def LwRxRyOffMemX16: FEXT_RRI16_mem_ins<0b10011, "lw", mem16, II_LW>, MayLoad{
// Purpose: Load Word (SP-Relative, Extended)
// To load an SP-relative word from memory as a signed value.
//
def LwRxSpImmX16: FEXT_RI16_SP_explicit_ins<0b10010, "lw", II_LW>, MayLoad{
let Uses = [SP];
}
def LwRxSpImmX16: FEXT_RRI16_mem_ins<0b10010, "lw", mem16sp, II_LW>, MayLoad;

def LwRxPcTcp16: FRI16_TCP_ins<0b10110, "lw", II_LW>, MayLoad;

Expand Down Expand Up @@ -1277,16 +1274,14 @@ def SubuRxRyRz16: FRRR16_ins<0b11, "subu", IIM16Alu>, ArithLogic16Defs<0>;
// Purpose: Store Word (Extended)
// To store a word to memory.
//
def SwRxRyOffMemX16:
FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore;
def SwRxRyOffMemX16: FEXT_RRI16_mem2_ins<0b11011, "sw", mem16, II_SW>, MayStore;

//
// Format: SW rx, offset(sp) MIPS16e
// Purpose: Store Word rx (SP-Relative)
// To store an SP-relative word to memory.
//
def SwRxSpImmX16: FEXT_RI16_SP_Store_explicit_ins
<0b11010, "sw", II_SW>, MayStore;
def SwRxSpImmX16: FEXT_RRI16_mem2_ins<0b11010, "sw", mem16sp, II_SW>, MayStore;

//
//
Expand Down Expand Up @@ -1340,22 +1335,21 @@ def: shift_rotate_reg16_pat<shl, SllvRxRy16>;
def: shift_rotate_reg16_pat<sra, SravRxRy16>;
def: shift_rotate_reg16_pat<srl, SrlvRxRy16>;

class LoadM16_pat<PatFrag OpNode, Instruction I> :
Mips16Pat<(OpNode addr16:$addr), (I addr16:$addr)>;
class LoadM16_pat<PatFrag OpNode, Instruction I, ComplexPattern Addr> :
Mips16Pat<(OpNode Addr:$addr), (I Addr:$addr)>;

def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16>;
def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16>;
def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16>;
def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16>;
def: LoadM16_pat<load, LwRxRyOffMemX16>;
def: LoadM16_pat<sextloadi8, LbRxRyOffMemX16, addr16>;
def: LoadM16_pat<zextloadi8, LbuRxRyOffMemX16, addr16>;
def: LoadM16_pat<sextloadi16, LhRxRyOffMemX16, addr16>;
def: LoadM16_pat<zextloadi16, LhuRxRyOffMemX16, addr16>;
def: LoadM16_pat<load, LwRxSpImmX16, addr16sp>;

class StoreM16_pat<PatFrag OpNode, Instruction I> :
Mips16Pat<(OpNode CPU16Regs:$r, addr16:$addr),
(I CPU16Regs:$r, addr16:$addr)>;
class StoreM16_pat<PatFrag OpNode, Instruction I, ComplexPattern Addr> :
Mips16Pat<(OpNode CPU16Regs:$r, Addr:$addr), (I CPU16Regs:$r, Addr:$addr)>;

def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16>;
def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16>;
def: StoreM16_pat<store, SwRxRyOffMemX16>;
def: StoreM16_pat<truncstorei8, SbRxRyOffMemX16, addr16>;
def: StoreM16_pat<truncstorei16, ShRxRyOffMemX16, addr16>;
def: StoreM16_pat<store, SwRxSpImmX16, addr16sp>;

// Unconditional branch
class UncondBranch16_pat<SDNode OpNode, Instruction I>:
Expand Down Expand Up @@ -1401,8 +1395,7 @@ class SetCC_I16<PatFrag cond_op, PatLeaf imm_type, Instruction I>:
(I CPU16Regs:$rx, imm_type:$imm16)>;


def: Mips16Pat<(i32 addr16:$addr),
(AddiuRxRyOffMemX16 addr16:$addr)>;
def: Mips16Pat<(i32 addr16sp:$addr), (AddiuRxRyOffMemX16 addr16sp:$addr)>;


// Large (>16 bit) immediate loads
Expand Down
10 changes: 8 additions & 2 deletions llvm/lib/Target/Mips/MipsISelDAGToDAG.cpp
Expand Up @@ -102,8 +102,14 @@ bool MipsDAGToDAGISel::selectIntAddrMSA(SDValue Addr, SDValue &Base,
return false;
}

bool MipsDAGToDAGISel::selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
SDValue &Offset, SDValue &Alias) {
bool MipsDAGToDAGISel::selectAddr16(SDValue Addr, SDValue &Base,
SDValue &Offset) {
llvm_unreachable("Unimplemented function.");
return false;
}

bool MipsDAGToDAGISel::selectAddr16SP(SDValue Addr, SDValue &Base,
SDValue &Offset) {
llvm_unreachable("Unimplemented function.");
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Target/Mips/MipsISelDAGToDAG.h
Expand Up @@ -75,8 +75,8 @@ class MipsDAGToDAGISel : public SelectionDAGISel {
virtual bool selectIntAddrMSA(SDValue Addr, SDValue &Base,
SDValue &Offset) const;

virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
SDValue &Offset, SDValue &Alias);
virtual bool selectAddr16(SDValue Addr, SDValue &Base, SDValue &Offset);
virtual bool selectAddr16SP(SDValue Addr, SDValue &Base, SDValue &Offset);

/// \brief Select constant vector splats.
virtual bool selectVSplat(SDNode *N, APInt &Imm,
Expand Down
12 changes: 0 additions & 12 deletions llvm/lib/Target/Mips/MipsMachineFunction.cpp
Expand Up @@ -53,18 +53,6 @@ unsigned MipsFunctionInfo::getGlobalBaseReg() {
return GlobalBaseReg = MF.getRegInfo().createVirtualRegister(RC);
}

bool MipsFunctionInfo::mips16SPAliasRegSet() const {
return Mips16SPAliasReg;
}
unsigned MipsFunctionInfo::getMips16SPAliasReg() {
// Return if it has already been initialized.
if (Mips16SPAliasReg)
return Mips16SPAliasReg;

const TargetRegisterClass *RC = &Mips::CPU16RegsRegClass;
return Mips16SPAliasReg = MF.getRegInfo().createVirtualRegister(RC);
}

void MipsFunctionInfo::createEhDataRegsFI() {
for (int I = 0; I < 4; ++I) {
const TargetRegisterClass *RC =
Expand Down
12 changes: 2 additions & 10 deletions llvm/lib/Target/Mips/MipsMachineFunction.h
Expand Up @@ -30,8 +30,8 @@ namespace llvm {
class MipsFunctionInfo : public MachineFunctionInfo {
public:
MipsFunctionInfo(MachineFunction &MF)
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), Mips16SPAliasReg(0),
VarArgsFrameIndex(0), CallsEhReturn(false), IsISR(false), SaveS2(false),
: MF(MF), SRetReturnReg(0), GlobalBaseReg(0), VarArgsFrameIndex(0),
CallsEhReturn(false), IsISR(false), SaveS2(false),
MoveF64ViaSpillFI(-1) {}

~MipsFunctionInfo();
Expand All @@ -42,9 +42,6 @@ class MipsFunctionInfo : public MachineFunctionInfo {
bool globalBaseRegSet() const;
unsigned getGlobalBaseReg();

bool mips16SPAliasRegSet() const;
unsigned getMips16SPAliasReg();

int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
void setVarArgsFrameIndex(int Index) { VarArgsFrameIndex = Index; }

Expand Down Expand Up @@ -101,11 +98,6 @@ class MipsFunctionInfo : public MachineFunctionInfo {
/// relocation models.
unsigned GlobalBaseReg;

/// Mips16SPAliasReg - keeps track of the virtual register initialized for
/// use as an alias for SP for use in load/store of halfword/byte from/to
/// the stack
unsigned Mips16SPAliasReg;

/// VarArgsFrameIndex - FrameIndex for start of varargs area.
int VarArgsFrameIndex;

Expand Down

0 comments on commit de7816b

Please sign in to comment.