mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-17 08:57:34 +00:00
[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:
parent
13e26da155
commit
da0860f78e
@ -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 {
|
||||
|
@ -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};
|
||||
}
|
||||
|
@ -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>;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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.");
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
26
test/MC/Mips/micromips-loadstore-unaligned.s
Normal file
26
test/MC/Mips/micromips-loadstore-unaligned.s
Normal 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)
|
Loading…
Reference in New Issue
Block a user