diff options
| author | Zoran Jovanovic <zoran.jovanovic@imgtec.com> | 2014-11-19 16:44:02 +0000 | 
|---|---|---|
| committer | Zoran Jovanovic <zoran.jovanovic@imgtec.com> | 2014-11-19 16:44:02 +0000 | 
| commit | a4c4b5fc0160fb1c3d550f17732690eeb96a3702 (patch) | |
| tree | ae25f48b126c74dd27f6072f6f06f1a2d6ecafde /llvm/lib/Target | |
| parent | b7e06becd96151e2fdee5b37b93df2001b90a221 (diff) | |
| download | bcm5719-llvm-a4c4b5fc0160fb1c3d550f17732690eeb96a3702.tar.gz bcm5719-llvm-a4c4b5fc0160fb1c3d550f17732690eeb96a3702.zip  | |
[mips][micromips] Implement SWM32 and LWM32 instructions
Differential Revision: http://reviews.llvm.org/D5519
llvm-svn: 222367
Diffstat (limited to 'llvm/lib/Target')
| -rw-r--r-- | llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 122 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp | 48 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp | 22 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h | 1 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 31 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h | 3 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MicroMipsInstrFormats.td | 13 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MicroMipsInstrInfo.td | 33 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 20 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MipsAsmPrinter.h | 1 | 
10 files changed, 288 insertions, 6 deletions
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index 1efbc05c34b..0c5b41f1b28 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -146,6 +146,9 @@ class MipsAsmParser : public MCTargetAsmParser {    MipsAsmParser::OperandMatchResultTy parseLSAImm(OperandVector &Operands); +  MipsAsmParser::OperandMatchResultTy +  parseRegisterList (OperandVector  &Operands); +    bool searchSymbolAlias(OperandVector &Operands);    bool parseOperand(OperandVector &, StringRef Mnemonic); @@ -424,7 +427,8 @@ private:      k_Memory,        /// Base + Offset Memory Address      k_PhysRegister,  /// A physical register from the Mips namespace      k_RegisterIndex, /// A register index in one or more RegKind. -    k_Token          /// A simple token +    k_Token,         /// A simple token +    k_RegList        /// A physical register list    } Kind;  public: @@ -459,12 +463,17 @@ private:      const MCExpr *Off;    }; +  struct RegListOp { +    SmallVector<unsigned, 10> *List; +  }; +    union {      struct Token Tok;      struct PhysRegOp PhysReg;      struct RegIdxOp RegIdx;      struct ImmOp Imm;      struct MemOp Mem; +    struct RegListOp RegList;    };    SMLoc StartLoc, EndLoc; @@ -751,6 +760,13 @@ public:      addExpr(Inst, Expr);    } +  void addRegListOperands(MCInst &Inst, unsigned N) const { +    assert(N == 1 && "Invalid number of operands!"); + +    for (auto RegNo : getRegList()) +      Inst.addOperand(MCOperand::CreateReg(RegNo)); +  } +    bool isReg() const override {      // As a special case until we sort out the definition of div/divu, pretend      // that $0/$zero are k_PhysRegister so that MCK_ZERO works correctly. @@ -783,6 +799,7 @@ public:      int64_t Val = getConstantImm();      return 1 <= Val && Val <= 4;    } +  bool isRegList() const { return Kind == k_RegList; }    StringRef getToken() const {      assert(Kind == k_Token && "Invalid access!"); @@ -824,6 +841,11 @@ public:      return static_cast<const MCConstantExpr *>(getMemOff())->getValue();    } +  const SmallVectorImpl<unsigned> &getRegList() const { +    assert((Kind == k_RegList) && "Invalid access!"); +    return *(RegList.List); +  } +    static std::unique_ptr<MipsOperand> CreateToken(StringRef Str, SMLoc S,                                                    MipsAsmParser &Parser) {      auto Op = make_unique<MipsOperand>(k_Token, Parser); @@ -919,6 +941,20 @@ public:      return Op;    } +  static std::unique_ptr<MipsOperand> +  CreateRegList(SmallVectorImpl<unsigned> &Regs, SMLoc StartLoc, SMLoc EndLoc, +                MipsAsmParser &Parser) { +    assert (Regs.size() > 0 && "Empty list not allowed"); + +    auto Op = make_unique<MipsOperand>(k_RegList, Parser); +    Op->RegList.List = new SmallVector<unsigned, 10>(); +    for (auto Reg : Regs) +      Op->RegList.List->push_back(Reg); +    Op->StartLoc = StartLoc; +    Op->EndLoc = EndLoc; +    return Op; +  } +    bool isGPRAsmReg() const {      return isRegIdx() && RegIdx.Kind & RegKind_GPR && RegIdx.Index <= 31;    } @@ -973,6 +1009,8 @@ public:      case k_Memory:        delete Mem.Base;        break; +    case k_RegList: +      delete RegList.List;      case k_PhysRegister:      case k_RegisterIndex:      case k_Token: @@ -1003,6 +1041,12 @@ public:      case k_Token:        OS << Tok.Data;        break; +    case k_RegList: +      OS << "RegList< "; +      for (auto Reg : (*RegList.List)) +        OS << Reg << " "; +      OS <<  ">"; +      break;      }    }  }; // class MipsOperand @@ -2522,6 +2566,82 @@ MipsAsmParser::parseLSAImm(OperandVector &Operands) {    return MatchOperand_Success;  } +MipsAsmParser::OperandMatchResultTy +MipsAsmParser::parseRegisterList(OperandVector &Operands) { +  MCAsmParser &Parser = getParser(); +  SmallVector<unsigned, 10> Regs; +  unsigned RegNo; +  unsigned PrevReg = Mips::NoRegister; +  bool RegRange = false; +  SmallVector<std::unique_ptr<MCParsedAsmOperand>, 8> TmpOperands; + +  if (Parser.getTok().isNot(AsmToken::Dollar)) +    return MatchOperand_ParseFail; + +  SMLoc S = Parser.getTok().getLoc(); +  while (parseAnyRegister(TmpOperands) == MatchOperand_Success) { +    SMLoc E = getLexer().getLoc(); +    MipsOperand &Reg = static_cast<MipsOperand &>(*TmpOperands.back()); +    RegNo = isGP64bit() ? Reg.getGPR64Reg() : Reg.getGPR32Reg(); +    if (RegRange) { +      // Remove last register operand because registers from register range +      // should be inserted first. +      if (RegNo == Mips::RA) { +        Regs.push_back(RegNo); +      } else { +        unsigned TmpReg = PrevReg + 1; +        while (TmpReg <= RegNo) { +          if ((TmpReg < Mips::S0) || (TmpReg > Mips::S7)) { +            Error(E, "invalid register operand"); +            return MatchOperand_ParseFail; +          } + +          PrevReg = TmpReg; +          Regs.push_back(TmpReg++); +        } +      } + +      RegRange = false; +    } else { +      if ((PrevReg == Mips::NoRegister) && (RegNo != Mips::S0) && +          (RegNo != Mips::RA)) { +        Error(E, "$16 or $31 expected"); +        return MatchOperand_ParseFail; +      } else if (((RegNo < Mips::S0) || (RegNo > Mips::S7)) && +                 (RegNo != Mips::FP) && (RegNo != Mips::RA)) { +        Error(E, "invalid register operand"); +        return MatchOperand_ParseFail; +      } else if ((PrevReg != Mips::NoRegister) && (RegNo != PrevReg + 1) && +                 (RegNo != Mips::FP) && (RegNo != Mips::RA)) { +        Error(E, "consecutive register numbers expected"); +        return MatchOperand_ParseFail; +      } + +      Regs.push_back(RegNo); +    } + +    if (Parser.getTok().is(AsmToken::Minus)) +      RegRange = true; + +    if (!Parser.getTok().isNot(AsmToken::Minus) && +        !Parser.getTok().isNot(AsmToken::Comma)) { +      Error(E, "',' or '-' expected"); +      return MatchOperand_ParseFail; +    } + +    Lex(); // Consume comma or minus +    if (Parser.getTok().isNot(AsmToken::Dollar)) +      break; + +    PrevReg = RegNo; +  } + +  SMLoc E = Parser.getTok().getLoc(); +  Operands.push_back(MipsOperand::CreateRegList(Regs, S, E, *this)); +  parseMemOperand(Operands); +  return MatchOperand_Success; +} +  MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) {    MCSymbolRefExpr::VariantKind VK = diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp index 5d594f1f426..48904ce2dee 100644 --- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp +++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp @@ -341,6 +341,10 @@ static DecodeStatus  DecodeBlezGroupBranch(MCInst &MI, InsnType insn, uint64_t Address,                         const void *Decoder); +static DecodeStatus DecodeRegListOperand(MCInst &Inst, unsigned Insn, +                                         uint64_t Address, +                                         const void *Decoder); +  namespace llvm {  extern Target TheMipselTarget, TheMipsTarget, TheMips64Target,                TheMips64elTarget; @@ -1034,12 +1038,23 @@ static DecodeStatus DecodeMemMMImm12(MCInst &Inst,    Reg = getReg(Decoder, Mips::GPR32RegClassID, Reg);    Base = getReg(Decoder, Mips::GPR32RegClassID, Base); -  if (Inst.getOpcode() == Mips::SC_MM) +  switch (Inst.getOpcode()) { +  case Mips::SWM32_MM: +  case Mips::LWM32_MM: +    if (DecodeRegListOperand(Inst, Insn, Address, Decoder) +        == MCDisassembler::Fail) +      return MCDisassembler::Fail; +    Inst.addOperand(MCOperand::CreateReg(Base)); +    Inst.addOperand(MCOperand::CreateImm(Offset)); +    break; +  case Mips::SC_MM:      Inst.addOperand(MCOperand::CreateReg(Reg)); - -  Inst.addOperand(MCOperand::CreateReg(Reg)); -  Inst.addOperand(MCOperand::CreateReg(Base)); -  Inst.addOperand(MCOperand::CreateImm(Offset)); +    // fallthrough +  default: +    Inst.addOperand(MCOperand::CreateReg(Reg)); +    Inst.addOperand(MCOperand::CreateReg(Base)); +    Inst.addOperand(MCOperand::CreateImm(Offset)); +  }    return MCDisassembler::Success;  } @@ -1375,3 +1390,26 @@ static DecodeStatus DecodeSimm18Lsl3(MCInst &Inst, unsigned Insn,    Inst.addOperand(MCOperand::CreateImm(SignExtend32<18>(Insn) * 8));    return MCDisassembler::Success;  } + +static DecodeStatus DecodeRegListOperand(MCInst &Inst, +                                         unsigned Insn, +                                         uint64_t Address, +                                         const void *Decoder) { +  unsigned Regs[] = {Mips::S0, Mips::S1, Mips::S2, Mips::S3, Mips::S4, Mips::S5, +                     Mips::S6, Mips::FP}; +  unsigned RegNum; + +  unsigned RegLst = fieldFromInstruction(Insn, 21, 5); +  // Empty register lists are not allowed. +  if (RegLst == 0) +    return MCDisassembler::Fail; + +  RegNum = RegLst & 0xf; +  for (unsigned i = 0; i < RegNum; i++) +    Inst.addOperand(MCOperand::CreateReg(Regs[i])); + +  if (RegLst & 0x10) +    Inst.addOperand(MCOperand::CreateReg(Mips::RA)); + +  return MCDisassembler::Success; +} diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp index 8c797517e31..ab6b22562ce 100644 --- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp +++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.cpp @@ -225,6 +225,18 @@ printMemOperand(const MCInst *MI, int opNum, raw_ostream &O) {    // Load/Store memory operands -- imm($reg)    // If PIC target the target is loaded as the    // pattern lw $25,%call16($28) + +  // opNum can be invalid if instruction had reglist as operand. +  // MemOperand is always last operand of instruction (base + offset). +  switch (MI->getOpcode()) { +  default: +    break; +  case Mips::SWM32_MM: +  case Mips::LWM32_MM: +    opNum = MI->getNumOperands() - 2; +    break; +  } +    printOperand(MI, opNum+1, O);    O << "(";    printOperand(MI, opNum, O); @@ -324,3 +336,13 @@ void MipsInstPrinter::printSaveRestore(const MCInst *MI, raw_ostream &O) {    }  } +void MipsInstPrinter:: +printRegisterList(const MCInst *MI, int opNum, raw_ostream &O) { +  // - 2 because register List is always first operand of instruction and it is +  // always followed by memory operand (base + offset). +  for (int i = opNum, e = MI->getNumOperands() - 2; i != e; ++i) { +    if (i != opNum) +      O << ", "; +    printRegName(O, MI->getOperand(i).getReg()); +  } +} diff --git a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h index d4f3253a912..42df0131d0a 100644 --- a/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h +++ b/llvm/lib/Target/Mips/InstPrinter/MipsInstPrinter.h @@ -107,6 +107,7 @@ private:                    unsigned OpNo1, raw_ostream &OS);    bool printAlias(const MCInst &MI, raw_ostream &OS);    void printSaveRestore(const MCInst *MI, raw_ostream &O); +  void printRegisterList(const MCInst *MI, int opNum, raw_ostream &O);  };  } // end namespace llvm diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp index 6fa56e81a73..d632c2736de 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp @@ -638,6 +638,17 @@ unsigned MipsMCCodeEmitter::  getMemEncodingMMImm12(const MCInst &MI, unsigned OpNo,                        SmallVectorImpl<MCFixup> &Fixups,                        const MCSubtargetInfo &STI) const { +  // opNum can be invalid if instruction had reglist as operand. +  // MemOperand is always last operand of instruction (base + offset). +  switch (MI.getOpcode()) { +  default: +    break; +  case Mips::SWM32_MM: +  case Mips::LWM32_MM: +    OpNo = MI.getNumOperands() - 2; +    break; +  } +    // 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, STI) << 16; @@ -757,4 +768,24 @@ MipsMCCodeEmitter::getUImm4AndValue(const MCInst &MI, unsigned OpNo,    llvm_unreachable("Unexpected value");  } +unsigned +MipsMCCodeEmitter::getRegisterListOpValue(const MCInst &MI, unsigned OpNo, +                                          SmallVectorImpl<MCFixup> &Fixups, +                                          const MCSubtargetInfo &STI) const { +  unsigned res = 0; + +  // Register list operand is always first operand of instruction and it is +  // placed before memory operand (register + imm). + +  for (unsigned I = OpNo, E = MI.getNumOperands() - 2; I < E; ++I) { +    unsigned Reg = MI.getOperand(I).getReg(); +    unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); +    if (RegNo != 31) +      res++; +    else +      res |= 0x10; +  } +  return res; +} +  #include "MipsGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h index df64ed48f65..9016fcfedc0 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h @@ -175,6 +175,9 @@ public:    unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl<MCFixup> &Fixups,                            const MCSubtargetInfo &STI) const; +  unsigned getRegisterListOpValue(const MCInst &MI, unsigned OpNo, +                                  SmallVectorImpl<MCFixup> &Fixups, +                                  const MCSubtargetInfo &STI) const;  }; // class MipsMCCodeEmitter  } // namespace llvm. diff --git a/llvm/lib/Target/Mips/MicroMipsInstrFormats.td b/llvm/lib/Target/Mips/MicroMipsInstrFormats.td index d1e02b8c5fe..59bf94989a1 100644 --- a/llvm/lib/Target/Mips/MicroMipsInstrFormats.td +++ b/llvm/lib/Target/Mips/MicroMipsInstrFormats.td @@ -804,3 +804,16 @@ class LWXS_FM_MM<bits<10> funct> {    let Inst{10}    = 0;    let Inst{9-0}   = funct;  } + +class LWM_FM_MM<bits<4> funct> : MMArch { +  bits<5> rt; +  bits<21> addr; + +  bits<32> Inst; + +  let Inst{31-26} = 0x8; +  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/llvm/lib/Target/Mips/MicroMipsInstrInfo.td b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td index 4a4cca9ba1b..e85462057ec 100644 --- a/llvm/lib/Target/Mips/MicroMipsInstrInfo.td +++ b/llvm/lib/Target/Mips/MicroMipsInstrInfo.td @@ -271,6 +271,35 @@ class LoadWordIndexedScaledMM<string opstr, RegisterOperand RO,    InstSE<(outs RO:$rd), (ins PtrRC:$base, PtrRC:$index),           !strconcat(opstr, "\t$rd, ${index}(${base})"), [], Itin, FrmFI>; +/// A list of registers used by load/store multiple instructions. +def RegListAsmOperand : AsmOperandClass { +  let Name = "RegList"; +  let ParserMethod = "parseRegisterList"; +} + +def reglist : Operand<i32> { +  let EncoderMethod = "getRegisterListOpValue"; +  let ParserMatchClass = RegListAsmOperand; +  let PrintMethod = "printRegisterList"; +  let DecoderMethod = "DecodeRegListOperand"; +} + +class StoreMultMM<string opstr, +            InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : +  InstSE<(outs), (ins reglist:$rt, mem_mm_12:$addr), +         !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { +  let DecoderMethod = "DecodeMemMMImm12"; +  let mayStore = 1; +} + +class LoadMultMM<string opstr, +            InstrItinClass Itin = NoItinerary, ComplexPattern Addr = addr> : +  InstSE<(outs reglist:$rt), (ins mem_mm_12:$addr), +          !strconcat(opstr, "\t$rt, $addr"), [], Itin, FrmI, opstr> { +  let DecoderMethod = "DecodeMemMMImm12"; +  let mayLoad = 1; +} +  def ADDU16_MM : ArithRMM16<"addu16", GPRMM16Opnd, 1, II_ADDU, add>,                  ARITH_FM_MM16<0>;  def SUBU16_MM : ArithRMM16<"subu16", GPRMM16Opnd, 0, II_SUBU, sub>, @@ -402,6 +431,10 @@ let DecoderNamespace = "MicroMips", Predicates = [InMicroMips] in {    def SWR_MM : StoreLeftRightMM<"swr", MipsSWR, GPR32Opnd, mem_mm_12>,                 LWL_FM_MM<0x9>; +  /// Load and Store Instructions - multiple +  def SWM32_MM  : StoreMultMM<"swm32">, LWM_FM_MM<0xd>; +  def LWM32_MM  : LoadMultMM<"lwm32">, LWM_FM_MM<0x5>; +    /// Move Conditional    def MOVZ_I_MM : MMRel, CMov_I_I_FT<"movz", GPR32Opnd, GPR32Opnd,                    NoItinerary>, ADD_FM_MM<0, 0x58>; diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp index 1b4cb616cc6..832fa05be0d 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp @@ -645,6 +645,18 @@ printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &O) {    // Load/Store memory operands -- imm($reg)    // If PIC target the target is loaded as the    // pattern lw $25,%call16($28) + +  // opNum can be invalid if instruction has reglist as operand. +  // MemOperand is always last operand of instruction (base + offset). +  switch (MI->getOpcode()) { +  default: +    break; +  case Mips::SWM32_MM: +  case Mips::LWM32_MM: +    opNum = MI->getNumOperands() - 2; +    break; +  } +    printOperand(MI, opNum+1, O);    O << "(";    printOperand(MI, opNum, O); @@ -668,6 +680,14 @@ printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,    O << Mips::MipsFCCToString((Mips::CondCode)MO.getImm());  } +void MipsAsmPrinter:: +printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O) { +  for (int i = opNum, e = MI->getNumOperands(); i != e; ++i) { +    if (i != opNum) O << ", "; +    printOperand(MI, i, O); +  } +} +  void MipsAsmPrinter::EmitStartOfAsmFile(Module &M) {    bool IsABICalls = Subtarget->isABICalls();    if (IsABICalls) { diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.h b/llvm/lib/Target/Mips/MipsAsmPrinter.h index 7f358d7b174..0582e210e9c 100644 --- a/llvm/lib/Target/Mips/MipsAsmPrinter.h +++ b/llvm/lib/Target/Mips/MipsAsmPrinter.h @@ -134,6 +134,7 @@ public:    void printMemOperandEA(const MachineInstr *MI, int opNum, raw_ostream &O);    void printFCCOperand(const MachineInstr *MI, int opNum, raw_ostream &O,                         const char *Modifier = nullptr); +  void printRegisterList(const MachineInstr *MI, int opNum, raw_ostream &O);    void EmitStartOfAsmFile(Module &M) override;    void EmitEndOfAsmFile(Module &M) override;    void PrintDebugValueComment(const MachineInstr *MI, raw_ostream &OS);  | 

