diff --git a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index d019f05f8b4..aa927bd77b0 100644 --- a/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -97,6 +97,8 @@ public: unsigned getMemEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups) const; + unsigned getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups) const; unsigned getSizeExtEncoding(const MCInst &MI, unsigned OpNo, SmallVectorImpl &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 &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 &Fixups) const { diff --git a/lib/Target/Mips/MicroMipsInstrFormats.td b/lib/Target/Mips/MicroMipsInstrFormats.td index 665b4d2d8b4..7d8c5135fa5 100644 --- a/lib/Target/Mips/MicroMipsInstrFormats.td +++ b/lib/Target/Mips/MicroMipsInstrFormats.td @@ -110,3 +110,16 @@ class LW_FM_MM op> : MMArch { let Inst{20-16} = addr{20-16}; let Inst{15-0} = addr{15-0}; } + +class LWL_FM_MM 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}; +} diff --git a/lib/Target/Mips/MicroMipsInstrInfo.td b/lib/Target/Mips/MicroMipsInstrInfo.td index 249d712045f..549d0e2b13c 100644 --- a/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/lib/Target/Mips/MicroMipsInstrInfo.td @@ -1,4 +1,34 @@ -let isCodeGenOnly = 1 in { +def addrimm12 : ComplexPattern; + +def simm12 : Operand { + let DecoderMethod = "DecodeSimm12"; +} + +def mem_mm_12 : Operand { + let PrintMethod = "printMemOperand"; + let MIOperandInfo = (ops GPR32, simm12); + let EncoderMethod = "getMemEncodingMMImm12"; + let ParserMatchClass = MipsMemAsmOperand; + let OperandType = "OPERAND_MEMORY"; +} + +let canFoldAsLoad = 1 in +class LoadLeftRightMM : + 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: + 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>; + } } diff --git a/lib/Target/Mips/MipsCodeEmitter.cpp b/lib/Target/Mips/MipsCodeEmitter.cpp index 813037ed254..eed11559256 100644 --- a/lib/Target/Mips/MipsCodeEmitter.cpp +++ b/lib/Target/Mips/MipsCodeEmitter.cpp @@ -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. diff --git a/lib/Target/Mips/MipsISelDAGToDAG.cpp b/lib/Target/Mips/MipsISelDAGToDAG.cpp index 0002a5f7c38..15e43d48cf3 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsISelDAGToDAG.cpp @@ -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."); diff --git a/lib/Target/Mips/MipsISelDAGToDAG.h b/lib/Target/Mips/MipsISelDAGToDAG.h index cf0f9c58aa9..a137a6080d0 100644 --- a/lib/Target/Mips/MipsISelDAGToDAG.h +++ b/lib/Target/Mips/MipsISelDAGToDAG.h @@ -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); diff --git a/lib/Target/Mips/MipsInstrInfo.td b/lib/Target/Mips/MipsInstrInfo.td index 65601b04de0..3806b33adb6 100644 --- a/lib/Target/Mips/MipsInstrInfo.td +++ b/lib/Target/Mips/MipsInstrInfo.td @@ -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 : Pat { let Predicates = [HasStdEnc]; @@ -516,7 +520,7 @@ class StoreLeftRight { def NAME : LoadLeftRight, - Requires<[NotN64, HasStdEnc]>; + Requires<[NotN64, HasStdEnc, NotInMicroMips]>; def _P8 : LoadLeftRight, Requires<[IsN64, HasStdEnc]> { let DecoderNamespace = "Mips64"; @@ -526,7 +530,7 @@ multiclass LoadLeftRightM { multiclass StoreLeftRightM { def NAME : StoreLeftRight, - Requires<[NotN64, HasStdEnc]>; + Requires<[NotN64, HasStdEnc, NotInMicroMips]>; def _P8 : StoreLeftRight, Requires<[IsN64, HasStdEnc]> { let DecoderNamespace = "Mips64"; diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp index 37fbc3d95a1..203196e6261 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.cpp +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.cpp @@ -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(Addr.getOperand(1)); + if (isInt<12>(CN->getSExtValue())) { + + // If the first operand is a FI, get the TargetFI Node + if (FrameIndexSDNode *FIN = dyn_cast + (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 MipsSEDAGToDAGISel::selectNode(SDNode *Node) { unsigned Opcode = Node->getOpcode(); SDLoc DL(Node); diff --git a/lib/Target/Mips/MipsSEISelDAGToDAG.h b/lib/Target/Mips/MipsSEISelDAGToDAG.h index 03ed1f97cf7..09a15b01f03 100644 --- a/lib/Target/Mips/MipsSEISelDAGToDAG.h +++ b/lib/Target/Mips/MipsSEISelDAGToDAG.h @@ -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 selectNode(SDNode *Node); virtual void processFunctionAfterISel(MachineFunction &MF); diff --git a/test/MC/Mips/micromips-loadstore-unaligned.s b/test/MC/Mips/micromips-loadstore-unaligned.s new file mode 100644 index 00000000000..ab1d8b935a1 --- /dev/null +++ b/test/MC/Mips/micromips-loadstore-unaligned.s @@ -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)