diff options
| -rw-r--r-- | llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp | 225 | ||||
| -rw-r--r-- | llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h | 2 | ||||
| -rw-r--r-- | llvm/test/MC/Mips/mips-fpu-instructions.s | 162 | ||||
| -rw-r--r-- | llvm/test/MC/Mips/mips-memory-instructions.s | 4 | 
4 files changed, 386 insertions, 7 deletions
| diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp index c038f4b5bea..6fdef524403 100644 --- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp +++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp @@ -27,6 +27,14 @@ namespace {  class MipsAsmParser : public MCTargetAsmParser { +  enum FpFormatTy { +    FP_FORMAT_NONE = -1, +    FP_FORMAT_S, +    FP_FORMAT_D, +    FP_FORMAT_L, +    FP_FORMAT_W +  } FpFormat; +    MCSubtargetInfo &STI;    MCAsmParser &Parser; @@ -42,6 +50,9 @@ class MipsAsmParser : public MCTargetAsmParser {    bool ParseInstruction(StringRef Name, SMLoc NameLoc,                          SmallVectorImpl<MCParsedAsmOperand*> &Operands); +  bool parseMathOperation(StringRef Name, SMLoc NameLoc, +                        SmallVectorImpl<MCParsedAsmOperand*> &Operands); +    bool ParseDirective(AsmToken DirectiveID);    MipsAsmParser::OperandMatchResultTy @@ -63,14 +74,31 @@ class MipsAsmParser : public MCTargetAsmParser {    bool parseMemOffset(const MCExpr *&Res);    bool parseRelocOperand(const MCExpr *&Res);    MCSymbolRefExpr::VariantKind getVariantKind(StringRef Symbol); +    bool isMips64() const {      return (STI.getFeatureBits() & Mips::FeatureMips64) != 0;    } +  bool isFP64() const { +    return (STI.getFeatureBits() & Mips::FeatureFP64Bit) != 0; +  } +    int matchRegisterName(StringRef Symbol);    int matchRegisterByNumber(unsigned RegNum, StringRef Mnemonic); +  void setFpFormat(FpFormatTy Format) { +    FpFormat = Format; +  } + +  void setDefaultFpFormat(); + +  void setFpFormat(StringRef Format); + +  FpFormatTy getFpFormat() {return FpFormat;} + +  bool requestsDoubleOperand(StringRef Mnemonic); +    unsigned getReg(int RC,int RegNo);  public: @@ -327,8 +355,59 @@ int MipsAsmParser::matchRegisterName(StringRef Name) {      return CC;    } +  if (Name[0] == 'f') { +    StringRef NumString = Name.substr(1); +    unsigned IntVal; +    if( NumString.getAsInteger(10, IntVal)) +      return -1; //not integer +    if (IntVal > 31) +      return -1; + +    FpFormatTy Format = getFpFormat(); + +    if (Format == FP_FORMAT_S || Format == FP_FORMAT_W) +      return getReg(Mips::FGR32RegClassID, IntVal); +    if (Format == FP_FORMAT_D) { +      if(isFP64()) { +        return getReg(Mips::FGR64RegClassID, IntVal); +      } +      //only even numbers available as register pairs +      if (( IntVal > 31) || (IntVal%2 !=  0)) +        return -1; +      return getReg(Mips::AFGR64RegClassID, IntVal/2); +    } +  } +    return -1;  } +void MipsAsmParser::setDefaultFpFormat() { + +  if (isMips64() || isFP64()) +    FpFormat = FP_FORMAT_D; +  else +    FpFormat = FP_FORMAT_S; +} + +bool MipsAsmParser::requestsDoubleOperand(StringRef Mnemonic){ + +  bool IsDouble = StringSwitch<bool>(Mnemonic.lower()) +    .Case("ldxc1", true) +    .Case("ldc1",  true) +    .Case("sdxc1", true) +    .Case("sdc1",  true) +    .Default(false); + +  return IsDouble; +} +void MipsAsmParser::setFpFormat(StringRef Format) { + +  FpFormat = StringSwitch<FpFormatTy>(Format.lower()) +    .Case(".s",  FP_FORMAT_S) +    .Case(".d",  FP_FORMAT_D) +    .Case(".l",  FP_FORMAT_L) +    .Case(".w",  FP_FORMAT_W) +    .Default(FP_FORMAT_NONE); +}  unsigned MipsAsmParser::getReg(int RC,int RegNo){    return *(getContext().getRegisterInfo().getRegClass(RC).begin() + RegNo); @@ -359,6 +438,13 @@ int MipsAsmParser::tryParseRegister(StringRef Mnemonic) {    } else if (Tok.is(AsmToken::Integer))      RegNum = matchRegisterByNumber(static_cast<unsigned> (Tok.getIntVal()),                                     Mnemonic.lower()); +    else +      return RegNum;  //error +  //64 bit div operations require Mips::ZERO instead of MIPS::ZERO_64 +  if (isMips64() && RegNum == Mips::ZERO_64) { +    if (Mnemonic.find("ddiv") != StringRef::npos) +      RegNum = Mips::ZERO; +  }    return RegNum;  } @@ -368,12 +454,21 @@ bool MipsAsmParser::    SMLoc S = Parser.getTok().getLoc();    int RegNo = -1; -  RegNo = tryParseRegister(Mnemonic); + +  //FIXME: we should make a more generic method for CCR +  if ((Mnemonic == "cfc1" || Mnemonic == "ctc1") +      && Operands.size() == 2 && Parser.getTok().is(AsmToken::Integer)){ +    RegNo = Parser.getTok().getIntVal();  //get the int value +    //at the moment only fcc0 is supported +    if (RegNo ==  0) +      RegNo = Mips::FCC0; +  } else +    RegNo = tryParseRegister(Mnemonic);    if (RegNo == -1)      return true;    Operands.push_back(MipsOperand::CreateReg(RegNo, S, -                     Parser.getTok().getLoc())); +      Parser.getTok().getLoc()));    Parser.Lex(); // Eat register token.    return false;  } @@ -550,9 +645,8 @@ bool MipsAsmParser::parseMemOffset(const MCExpr *&Res) {    case AsmToken::Minus:    case AsmToken::Plus:      return (getParser().ParseExpression(Res)); -  case AsmToken::Percent: { +  case AsmToken::Percent:      return parseRelocOperand(Res); -  }    case AsmToken::LParen:      return false;  //it's probably assuming 0    } @@ -641,12 +735,131 @@ MCSymbolRefExpr::VariantKind MipsAsmParser::getVariantKind(StringRef Symbol) {    return VK;  } +int ConvertCcString(StringRef CondString){ + +  int CC = StringSwitch<unsigned>(CondString) +      .Case(".f",    0) +      .Case(".un",   1) +      .Case(".eq",   2) +      .Case(".ueq",  3) +      .Case(".olt",  4) +      .Case(".ult",  5) +      .Case(".ole",  6) +      .Case(".ule",  7) +      .Case(".sf",   8) +      .Case(".ngle", 9) +      .Case(".seq",  10) +      .Case(".ngl",  11) +      .Case(".lt",   12) +      .Case(".nge",  13) +      .Case(".le",   14) +      .Case(".ngt",  15) +      .Default(-1); + +  return CC; +} + +bool MipsAsmParser:: +parseMathOperation(StringRef Name, SMLoc NameLoc, +                        SmallVectorImpl<MCParsedAsmOperand*> &Operands) { +  //split the format +  size_t Start = Name.find('.'), Next = Name.rfind('.'); +  StringRef Format1 = Name.slice(Start, Next); +  //and add the first format to the operands +  Operands.push_back(MipsOperand::CreateToken(Format1, NameLoc)); +  //now for the second format +  StringRef Format2 = Name.slice(Next, StringRef::npos); +  Operands.push_back(MipsOperand::CreateToken(Format2, NameLoc)); + +  //set the format for the first register +  setFpFormat(Format1); + +  // Read the remaining operands. +  if (getLexer().isNot(AsmToken::EndOfStatement)) { +    // Read the first operand. +    if (ParseOperand(Operands, Name)) { +      SMLoc Loc = getLexer().getLoc(); +      Parser.EatToEndOfStatement(); +      return Error(Loc, "unexpected token in argument list"); +    } + +    if (getLexer().isNot(AsmToken::Comma)) { +      SMLoc Loc = getLexer().getLoc(); +      Parser.EatToEndOfStatement(); +      return Error(Loc, "unexpected token in argument list"); + +    } +    Parser.Lex();  // Eat the comma. + +    //set the format for the first register +    setFpFormat(Format2); + +    // Parse and remember the operand. +    if (ParseOperand(Operands, Name)) { +      SMLoc Loc = getLexer().getLoc(); +      Parser.EatToEndOfStatement(); +      return Error(Loc, "unexpected token in argument list"); +    } +  } + +  if (getLexer().isNot(AsmToken::EndOfStatement)) { +    SMLoc Loc = getLexer().getLoc(); +    Parser.EatToEndOfStatement(); +    return Error(Loc, "unexpected token in argument list"); +  } + +  Parser.Lex(); // Consume the EndOfStatement +  return false; +} +  bool MipsAsmParser::  ParseInstruction(StringRef Name, SMLoc NameLoc,                   SmallVectorImpl<MCParsedAsmOperand*> &Operands) { - -  //first operand is a instruction mnemonic +  //floating point instructions: should register be treated as double? +  if (requestsDoubleOperand(Name)) { +    setFpFormat(FP_FORMAT_D);    Operands.push_back(MipsOperand::CreateToken(Name, NameLoc)); +  } +  else { +    setDefaultFpFormat(); +    // Create the leading tokens for the mnemonic, split by '.' characters. +    size_t Start = 0, Next = Name.find('.'); +    StringRef Mnemonic = Name.slice(Start, Next); + +    Operands.push_back(MipsOperand::CreateToken(Mnemonic, NameLoc)); + +    if (Next != StringRef::npos) { +      //there is a format token in mnemonic +      //StringRef Rest = Name.slice(Next, StringRef::npos); +      size_t Dot = Name.find('.', Next+1); +      StringRef Format = Name.slice(Next, Dot); +      if (Dot == StringRef::npos) //only one '.' in a string, it's a format +        Operands.push_back(MipsOperand::CreateToken(Format, NameLoc)); +      else { +        if (Name.startswith("c.")){ +          // floating point compare, add '.' and immediate represent for cc +          Operands.push_back(MipsOperand::CreateToken(".", NameLoc)); +          int Cc = ConvertCcString(Format); +          if (Cc == -1) { +            return Error(NameLoc, "Invalid conditional code"); +          } +          SMLoc E = SMLoc::getFromPointer( +              Parser.getTok().getLoc().getPointer() -1 ); +          Operands.push_back(MipsOperand::CreateImm( +              MCConstantExpr::Create(Cc, getContext()), NameLoc, E)); +        } else { +          //trunc, ceil, floor ... +          return parseMathOperation(Name, NameLoc, Operands); +        } + +        //the rest is a format +        Format = Name.slice(Dot, StringRef::npos); +        Operands.push_back(MipsOperand::CreateToken(Format, NameLoc)); +      } + +      setFpFormat(Format); +    } +  }    // Read the remaining operands.    if (getLexer().isNot(AsmToken::EndOfStatement)) { diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h index 234455e0c7f..96033276d22 100644 --- a/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h +++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsBaseInfo.h @@ -122,7 +122,7 @@ inline static unsigned getMipsRegisterNumbering(unsigned RegEnum)  {    switch (RegEnum) {    case Mips::ZERO: case Mips::ZERO_64: case Mips::F0: case Mips::D0_64: -  case Mips::D0: +  case Mips::D0:   case Mips::FCC0:      return 0;    case Mips::AT: case Mips::AT_64: case Mips::F1: case Mips::D1_64:      return 1; diff --git a/llvm/test/MC/Mips/mips-fpu-instructions.s b/llvm/test/MC/Mips/mips-fpu-instructions.s new file mode 100644 index 00000000000..ce8024d45b5 --- /dev/null +++ b/llvm/test/MC/Mips/mips-fpu-instructions.s @@ -0,0 +1,162 @@ +# RUN: llvm-mc  %s -triple=mipsel-unknown-linux -show-encoding -mcpu=mips32r2 | FileCheck %s +# Check that the assembler can handle the documented syntax +# for FPU instructions. +# CHECK: .section __TEXT,__text,regular,pure_instructions +#------------------------------------------------------------------------------ +# FP aritmetic  instructions +#------------------------------------------------------------------------------ + +# CHECK:  abs.d      $f12, $f14         # encoding: [0x05,0x73,0x20,0x46] +# CHECK:  abs.s      $f6, $f7           # encoding: [0x85,0x39,0x00,0x46] +# CHECK:  add.d      $f8, $f12, $f14    # encoding: [0x00,0x62,0x2e,0x46] +# CHECK:  add.s      $f9, $f6, $f7      # encoding: [0x40,0x32,0x07,0x46] +# CHECK:  floor.w.d  $f12, $f14         # encoding: [0x0f,0x73,0x20,0x46] +# CHECK:  floor.w.s  $f6, $f7           # encoding: [0x8f,0x39,0x00,0x46] +# CHECK:  ceil.w.d   $f12, $f14         # encoding: [0x0e,0x73,0x20,0x46] +# CHECK:  ceil.w.s   $f6, $f7           # encoding: [0x8e,0x39,0x00,0x46] +# CHECK:  mul.d      $f8, $f12, $f14    # encoding: [0x02,0x62,0x2e,0x46] +# CHECK:  mul.s      $f9, $f6, $f7      # encoding: [0x42,0x32,0x07,0x46] +# CHECK:  neg.d      $f12, $f14         # encoding: [0x07,0x73,0x20,0x46] +# CHECK:  neg.s      $f6, $f7           # encoding: [0x87,0x39,0x00,0x46] +# CHECK:  round.w.d  $f12, $f14         # encoding: [0x0c,0x73,0x20,0x46] +# CHECK:  round.w.s  $f6, $f7           # encoding: [0x8c,0x39,0x00,0x46] +# CHECK:  sqrt.d     $f12, $f14         # encoding: [0x04,0x73,0x20,0x46] +# CHECK:  sqrt.s     $f6, $f7           # encoding: [0x84,0x39,0x00,0x46] +# CHECK:  sub.d      $f8, $f12, $f14    # encoding: [0x01,0x62,0x2e,0x46] +# CHECK:  sub.s      $f9, $f6, $f7      # encoding: [0x41,0x32,0x07,0x46] +# CHECK:  trunc.w.d  $f12, $f14         # encoding: [0x0d,0x73,0x20,0x46] +# CHECK:  trunc.w.s  $f6, $f7           # encoding: [0x8d,0x39,0x00,0x46] + +    abs.d      $f12,$f14 +    abs.s      $f6,$f7 +    add.d      $f8,$f12,$f14 +    add.s      $f9,$f6,$f7 +    floor.w.d  $f12,$f14 +    floor.w.s  $f6,$f7 +    ceil.w.d   $f12,$f14 +    ceil.w.s   $f6,$f7 +    mul.d      $f8,$f12,$f14 +    mul.s      $f9,$f6, $f7 +    neg.d      $f12,$f14 +    neg.s      $f6,$f7 +    round.w.d  $f12,$f14 +    round.w.s  $f6,$f7 +    sqrt.d     $f12,$f14 +    sqrt.s     $f6,$f7 +    sub.d      $f8,$f12,$f14 +    sub.s      $f9,$f6,$f7 +    trunc.w.d  $f12,$f14 +    trunc.w.s  $f6,$f7 + +#------------------------------------------------------------------------------ +# FP compare instructions +#------------------------------------------------------------------------------ + +# CHECK:  c.eq.d    $f12, $f14        # encoding: [0x32,0x60,0x2e,0x46] +# CHECK:  c.eq.s    $f6, $f7          # encoding: [0x32,0x30,0x07,0x46] +# CHECK:  c.f.d     $f12, $f14        # encoding: [0x30,0x60,0x2e,0x46] +# CHECK:  c.f.s     $f6, $f7          # encoding: [0x30,0x30,0x07,0x46] +# CHECK:  c.le.d    $f12, $f14        # encoding: [0x3e,0x60,0x2e,0x46] +# CHECK:  c.le.s    $f6, $f7          # encoding: [0x3e,0x30,0x07,0x46] +# CHECK:  c.lt.d    $f12, $f14        # encoding: [0x3c,0x60,0x2e,0x46] +# CHECK:  c.lt.s    $f6, $f7          # encoding: [0x3c,0x30,0x07,0x46] +# CHECK:  c.nge.d   $f12, $f14        # encoding: [0x3d,0x60,0x2e,0x46] +# CHECK:  c.nge.s   $f6, $f7          # encoding: [0x3d,0x30,0x07,0x46] +# CHECK:  c.ngl.d   $f12, $f14        # encoding: [0x3b,0x60,0x2e,0x46] +# CHECK:  c.ngl.s   $f6, $f7          # encoding: [0x3b,0x30,0x07,0x46] +# CHECK:  c.ngle.d  $f12, $f14        # encoding: [0x39,0x60,0x2e,0x46] +# CHECK:  c.ngle.s  $f6, $f7          # encoding: [0x39,0x30,0x07,0x46] +# CHECK:  c.ngt.d   $f12, $f14        # encoding: [0x3f,0x60,0x2e,0x46] +# CHECK:  c.ngt.s   $f6, $f7          # encoding: [0x3f,0x30,0x07,0x46] +# CHECK:  c.ole.d   $f12, $f14        # encoding: [0x36,0x60,0x2e,0x46] +# CHECK:  c.ole.s   $f6, $f7          # encoding: [0x36,0x30,0x07,0x46] +# CHECK:  c.olt.d   $f12, $f14        # encoding: [0x34,0x60,0x2e,0x46] +# CHECK:  c.olt.s   $f6, $f7          # encoding: [0x34,0x30,0x07,0x46] +# CHECK:  c.seq.d   $f12, $f14        # encoding: [0x3a,0x60,0x2e,0x46] +# CHECK:  c.seq.s   $f6, $f7          # encoding: [0x3a,0x30,0x07,0x46] +# CHECK:  c.sf.d    $f12, $f14        # encoding: [0x38,0x60,0x2e,0x46] +# CHECK:  c.sf.s    $f6, $f7          # encoding: [0x38,0x30,0x07,0x46] +# CHECK:  c.ueq.d   $f12, $f14        # encoding: [0x33,0x60,0x2e,0x46] +# CHECK:  c.ueq.s   $f28, $f18        # encoding: [0x33,0xe0,0x12,0x46] +# CHECK:  c.ule.d   $f12, $f14        # encoding: [0x37,0x60,0x2e,0x46] +# CHECK:  c.ule.s   $f6, $f7          # encoding: [0x37,0x30,0x07,0x46] +# CHECK:  c.ult.d   $f12, $f14        # encoding: [0x35,0x60,0x2e,0x46] +# CHECK:  c.ult.s   $f6, $f7          # encoding: [0x35,0x30,0x07,0x46] +# CHECK:  c.un.d    $f12, $f14        # encoding: [0x31,0x60,0x2e,0x46] +# CHECK:  c.un.s    $f6, $f7          # encoding: [0x31,0x30,0x07,0x46] + +     c.eq.d    $f12,$f14 +     c.eq.s    $f6,$f7 +     c.f.d     $f12,$f14 +     c.f.s     $f6,$f7 +     c.le.d    $f12,$f14 +     c.le.s    $f6,$f7 +     c.lt.d    $f12,$f14 +     c.lt.s    $f6,$f7 +     c.nge.d   $f12,$f14 +     c.nge.s   $f6,$f7 +     c.ngl.d   $f12,$f14 +     c.ngl.s   $f6,$f7 +     c.ngle.d  $f12,$f14 +     c.ngle.s  $f6,$f7 +     c.ngt.d   $f12,$f14 +     c.ngt.s   $f6,$f7 +     c.ole.d   $f12,$f14 +     c.ole.s   $f6,$f7 +     c.olt.d   $f12,$f14 +     c.olt.s   $f6,$f7 +     c.seq.d   $f12,$f14 +     c.seq.s   $f6,$f7 +     c.sf.d    $f12,$f14 +     c.sf.s    $f6,$f7 +     c.ueq.d   $f12,$f14 +     c.ueq.s   $f28,$f18 +     c.ule.d   $f12,$f14 +     c.ule.s   $f6,$f7 +     c.ult.d   $f12,$f14 +     c.ult.s   $f6,$f7 +     c.un.d    $f12,$f14 +     c.un.s    $f6,$f7 + +#------------------------------------------------------------------------------ +# FP convert instructions +#------------------------------------------------------------------------------ +# CHECK:  cvt.d.s   $f6, $f7          # encoding: [0xa1,0x39,0x00,0x46] +# CHECK:  cvt.d.w   $f12, $f14        # encoding: [0x21,0x73,0x80,0x46] +# CHECK:  cvt.s.d   $f12, $f14        # encoding: [0x20,0x73,0x20,0x46] +# CHECK:  cvt.s.w   $f6, $f7          # encoding: [0xa0,0x39,0x80,0x46] +# CHECK:  cvt.w.d   $f12, $f14        # encoding: [0x24,0x73,0x20,0x46] +# CHECK:  cvt.w.s   $f6, $f7          # encoding: [0xa4,0x39,0x00,0x46] + +  cvt.d.s   $f6,$f7 +  cvt.d.w   $f12,$f14 +  cvt.s.d   $f12,$f14 +  cvt.s.w   $f6,$f7 +  cvt.w.d   $f12,$f14 +  cvt.w.s   $f6,$f7 + +#------------------------------------------------------------------------------ +# FP move instructions +#------------------------------------------------------------------------------ + +# CHECK:  cfc1    $6, $fcc0            # encoding: [0x00,0x00,0x46,0x44] +# CHECK:  mfc1    $6, $f7              # encoding: [0x00,0x38,0x06,0x44] +# CHECK:  mfhi    $5                   # encoding: [0x10,0x28,0x00,0x00] +# CHECK:  mflo    $5                   # encoding: [0x12,0x28,0x00,0x00] +# CHECK:  mov.d   $f6, $f8             # encoding: [0x86,0x41,0x20,0x46] +# CHECK:  mov.s   $f6, $f7             # encoding: [0x86,0x39,0x00,0x46] +# CHECK:  mtc1    $6, $f7              # encoding: [0x00,0x38,0x86,0x44] +# CHECK:  mthi    $7                   # encoding: [0x11,0x00,0xe0,0x00] +# CHECK:  mtlo    $7                   # encoding: [0x13,0x00,0xe0,0x00] +# CHECK:  swc1    $f9, 9158($7)        # encoding: [0xc6,0x23,0xe9,0xe4] + +   cfc1    $a2,$0 +   mfc1    $a2,$f7 +   mfhi    $a1 +   mflo    $a1 +   mov.d   $f6,$f8 +   mov.s   $f6,$f7 +   mtc1    $a2,$f7 +   mthi    $a3 +   mtlo    $a3 +   swc1    $f9,9158($a3) diff --git a/llvm/test/MC/Mips/mips-memory-instructions.s b/llvm/test/MC/Mips/mips-memory-instructions.s index 48678194c5d..b5f1267ef38 100644 --- a/llvm/test/MC/Mips/mips-memory-instructions.s +++ b/llvm/test/MC/Mips/mips-memory-instructions.s @@ -10,11 +10,15 @@  # CHECK:  sh      $4, 16($5)      # encoding: [0x10,0x00,0xa4,0xa4]  # CHECK:  sw      $4, 16($5)      # encoding: [0x10,0x00,0xa4,0xac]  # CHECK:  sw      $7,  0($5)      # encoding: [0x00,0x00,0xa7,0xac] +# CHECK:  swc1    $f2, 16($5)     # encoding: [0x10,0x00,0xa2,0xe4] +# CHECK:  swl     $4, 16($5)      # encoding: [0x10,0x00,0xa4,0xa8]       sb   $4, 16($5)       sc   $4, 16($5)       sh   $4, 16($5)       sw   $4, 16($5)       sw   $7,   ($5) +     swc1 $f2, 16($5) +     swl  $4, 16($5)  #------------------------------------------------------------------------------  # Memory load instructions | 

