[Mips] Support for unaligned load/store microMips instructions

This includes instructions lwl, lwr, swl and swr.

Patch by Zoran Jovnovic


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@188312 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jack Carter 2013-08-13 20:19:16 +00:00
parent 13e26da155
commit da0860f78e
10 changed files with 157 additions and 3 deletions

View File

@ -97,6 +97,8 @@ public:
unsigned getMemEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const;
unsigned getSizeInsEncoding(const MCInst &MI, unsigned OpNo,
@ -212,6 +214,7 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
LowerDextDins(TmpInst);
}
unsigned long N = Fixups.size();
uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups);
// Check for unimplemented opcodes.
@ -224,6 +227,8 @@ EncodeInstruction(const MCInst &MI, raw_ostream &OS,
if (STI.getFeatureBits() & Mips::FeatureMicroMips) {
int NewOpcode = Mips::Std2MicroMips (Opcode, Mips::Arch_micromips);
if (NewOpcode != -1) {
if (Fixups.size() > N)
Fixups.pop_back();
Opcode = NewOpcode;
TmpInst.setOpcode (NewOpcode);
Binary = getBinaryCodeForInstr(TmpInst, Fixups);
@ -417,6 +422,17 @@ MipsMCCodeEmitter::getMemEncoding(const MCInst &MI, unsigned OpNo,
return (OffBits & 0xFFFF) | RegBits;
}
unsigned MipsMCCodeEmitter::
getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const {
// Base register is encoded in bits 20-16, offset is encoded in bits 11-0.
assert(MI.getOperand(OpNo).isReg());
unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups) << 16;
unsigned OffBits = getMachineOpValue(MI, MI.getOperand(OpNo+1), Fixups);
return (OffBits & 0x0FFF) | RegBits;
}
unsigned
MipsMCCodeEmitter::getSizeExtEncoding(const MCInst &MI, unsigned OpNo,
SmallVectorImpl<MCFixup> &Fixups) const {

View File

@ -110,3 +110,16 @@ class LW_FM_MM<bits<6> op> : MMArch {
let Inst{20-16} = addr{20-16};
let Inst{15-0} = addr{15-0};
}
class LWL_FM_MM<bits<4> funct> {
bits<5> rt;
bits<21> addr;
bits<32> Inst;
let Inst{31-26} = 0x18;
let Inst{25-21} = rt;
let Inst{20-16} = addr{20-16};
let Inst{15-12} = funct;
let Inst{11-0} = addr{11-0};
}

View File

@ -1,4 +1,34 @@
let isCodeGenOnly = 1 in {
def addrimm12 : ComplexPattern<iPTR, 2, "selectIntAddrMM", [frameindex]>;
def simm12 : Operand<i32> {
let DecoderMethod = "DecodeSimm12";
}
def mem_mm_12 : Operand<i32> {
let PrintMethod = "printMemOperand";
let MIOperandInfo = (ops GPR32, simm12);
let EncoderMethod = "getMemEncodingMMImm12";
let ParserMatchClass = MipsMemAsmOperand;
let OperandType = "OPERAND_MEMORY";
}
let canFoldAsLoad = 1 in
class LoadLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
Operand MemOpnd> :
InstSE<(outs RO:$rt), (ins MemOpnd:$addr, RO:$src),
!strconcat(opstr, "\t$rt, $addr"),
[(set RO:$rt, (OpNode addrimm12:$addr, RO:$src))],
NoItinerary, FrmI> {
string Constraints = "$src = $rt";
}
class StoreLeftRightMM<string opstr, SDNode OpNode, RegisterOperand RO,
Operand MemOpnd>:
InstSE<(outs), (ins RO:$rt, MemOpnd:$addr),
!strconcat(opstr, "\t$rt, $addr"),
[(OpNode RO:$rt, addrimm12:$addr)], NoItinerary, FrmI>;
let DecoderNamespace = "MicroMips" in {
/// Arithmetic Instructions (ALU Immediate)
def ADDiu_MM : MMRel, ArithLogicI<"addiu", simm16, GPR32Opnd>,
ADDI_FM_MM<0xc>;
@ -64,4 +94,16 @@ let isCodeGenOnly = 1 in {
defm SB_MM : StoreM<"sb", GPR32Opnd, truncstorei8>, MMRel, LW_FM_MM<0x6>;
defm SH_MM : StoreM<"sh", GPR32Opnd, truncstorei16>, MMRel, LW_FM_MM<0xe>;
defm SW_MM : StoreM<"sw", GPR32Opnd>, MMRel, LW_FM_MM<0x3e>;
/// Load and Store Instructions - unaligned
let Predicates = [InMicroMips] in {
def LWL_MM : LoadLeftRightMM<"lwl", MipsLWL, GPR32Opnd, mem_mm_12>,
LWL_FM_MM<0x0>;
def LWR_MM : LoadLeftRightMM<"lwr", MipsLWR, GPR32Opnd, mem_mm_12>,
LWL_FM_MM<0x1>;
def SWL_MM : StoreLeftRightMM<"swl", MipsSWL, GPR32Opnd, mem_mm_12>,
LWL_FM_MM<0x8>;
def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>,
LWL_FM_MM<0x9>;
}
}

View File

@ -108,6 +108,7 @@ private:
unsigned getBranchTargetOpValue(const MachineInstr &MI, unsigned OpNo) const;
unsigned getMemEncoding(const MachineInstr &MI, unsigned OpNo) const;
unsigned getMemEncodingMMImm12(const MachineInstr &MI, unsigned OpNo) const;
unsigned getSizeExtEncoding(const MachineInstr &MI, unsigned OpNo) const;
unsigned getSizeInsEncoding(const MachineInstr &MI, unsigned OpNo) const;
@ -201,6 +202,12 @@ unsigned MipsCodeEmitter::getMemEncoding(const MachineInstr &MI,
return (getMachineOpValue(MI, MI.getOperand(OpNo+1)) & 0xFFFF) | RegBits;
}
unsigned MipsCodeEmitter::getMemEncodingMMImm12(const MachineInstr &MI,
unsigned OpNo) const {
llvm_unreachable("Unimplemented function.");
return 0;
}
unsigned MipsCodeEmitter::getSizeExtEncoding(const MachineInstr &MI,
unsigned OpNo) const {
// size is encoded as size-1.

View File

@ -81,6 +81,12 @@ bool MipsDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base,
return false;
}
bool MipsDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
llvm_unreachable("Unimplemented function.");
return false;
}
bool MipsDAGToDAGISel::selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
SDValue &Offset, SDValue &Alias) {
llvm_unreachable("Unimplemented function.");

View File

@ -65,6 +65,9 @@ private:
virtual bool selectIntAddr(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
virtual bool selectAddr16(SDNode *Parent, SDValue N, SDValue &Base,
SDValue &Offset, SDValue &Alias);

View File

@ -182,6 +182,10 @@ def NoNaNsFPMath : Predicate<"TM.Options.NoNaNsFPMath">,
def HasStdEnc : Predicate<"Subtarget.hasStandardEncoding()">,
AssemblerPredicate<"!FeatureMips16">;
def NotDSP : Predicate<"!Subtarget.hasDSP()">;
def InMicroMips : Predicate<"Subtarget.inMicroMipsMode()">,
AssemblerPredicate<"FeatureMicroMips">;
def NotInMicroMips : Predicate<"!Subtarget.inMicroMipsMode()">,
AssemblerPredicate<"!FeatureMicroMips">;
class MipsPat<dag pattern, dag result> : Pat<pattern, result> {
let Predicates = [HasStdEnc];
@ -516,7 +520,7 @@ class StoreLeftRight<string opstr, SDNode OpNode, RegisterOperand RO,
multiclass LoadLeftRightM<string opstr, SDNode OpNode, RegisterOperand RO> {
def NAME : LoadLeftRight<opstr, OpNode, RO, mem>,
Requires<[NotN64, HasStdEnc]>;
Requires<[NotN64, HasStdEnc, NotInMicroMips]>;
def _P8 : LoadLeftRight<opstr, OpNode, RO, mem64>,
Requires<[IsN64, HasStdEnc]> {
let DecoderNamespace = "Mips64";
@ -526,7 +530,7 @@ multiclass LoadLeftRightM<string opstr, SDNode OpNode, RegisterOperand RO> {
multiclass StoreLeftRightM<string opstr, SDNode OpNode, RegisterOperand RO> {
def NAME : StoreLeftRight<opstr, OpNode, RO, mem>,
Requires<[NotN64, HasStdEnc]>;
Requires<[NotN64, HasStdEnc, NotInMicroMips]>;
def _P8 : StoreLeftRight<opstr, OpNode, RO, mem64>,
Requires<[IsN64, HasStdEnc]> {
let DecoderNamespace = "Mips64";

View File

@ -314,6 +314,37 @@ bool MipsSEDAGToDAGISel::selectIntAddr(SDValue Addr, SDValue &Base,
selectAddrDefault(Addr, Base, Offset);
}
/// Used on microMIPS Load/Store unaligned instructions (12-bit offset)
bool MipsSEDAGToDAGISel::selectAddrRegImm12(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
EVT ValTy = Addr.getValueType();
// Addresses of the form FI+const or FI|const
if (CurDAG->isBaseWithConstantOffset(Addr)) {
ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1));
if (isInt<12>(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);
else
Base = Addr.getOperand(0);
Offset = CurDAG->getTargetConstant(CN->getZExtValue(), ValTy);
return true;
}
}
return false;
}
bool MipsSEDAGToDAGISel::selectIntAddrMM(SDValue Addr, SDValue &Base,
SDValue &Offset) const {
return selectAddrRegImm12(Addr, Base, Offset) ||
selectAddrDefault(Addr, Base, Offset);
}
std::pair<bool, SDNode*> MipsSEDAGToDAGISel::selectNode(SDNode *Node) {
unsigned Opcode = Node->getOpcode();
SDLoc DL(Node);

View File

@ -47,6 +47,12 @@ private:
virtual bool selectIntAddr(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
virtual bool selectAddrRegImm12(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
virtual bool selectIntAddrMM(SDValue Addr, SDValue &Base,
SDValue &Offset) const;
virtual std::pair<bool, SDNode*> selectNode(SDNode *Node);
virtual void processFunctionAfterISel(MachineFunction &MF);

View File

@ -0,0 +1,26 @@
# RUN: llvm-mc %s -triple=mipsel-unknown-linux -show-encoding \
# RUN: -mattr=micromips | FileCheck -check-prefix=CHECK-EL %s
# RUN: llvm-mc %s -triple=mips-unknown-linux -show-encoding \
# RUN: -mattr=micromips | FileCheck -check-prefix=CHECK-EB %s
# Check that the assembler can handle the documented syntax
# for loads and stores.
#------------------------------------------------------------------------------
# Load and Store unaligned instructions
#------------------------------------------------------------------------------
# Little endian
#------------------------------------------------------------------------------
# CHECK-EL: lwl $4, 16($5) # encoding: [0x85,0x60,0x10,0x00]
# CHECK-EL: lwr $4, 16($5) # encoding: [0x85,0x60,0x10,0x10]
# CHECK-EL: swl $4, 16($5) # encoding: [0x85,0x60,0x10,0x80]
# CHECK-EL: swr $4, 16($5) # encoding: [0x85,0x60,0x10,0x90]
#------------------------------------------------------------------------------
# Big endian
#------------------------------------------------------------------------------
# CHECK-EB: lwl $4, 16($5) # encoding: [0x60,0x85,0x00,0x10]
# CHECK-EB: lwr $4, 16($5) # encoding: [0x60,0x85,0x10,0x10]
# CHECK-EB: swl $4, 16($5) # encoding: [0x60,0x85,0x80,0x10]
# CHECK-EB: swr $4, 16($5) # encoding: [0x60,0x85,0x90,0x10]
lwl $4, 16($5)
lwr $4, 16($5)
swl $4, 16($5)
swr $4, 16($5)