diff --git a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp --- a/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp +++ b/llvm/lib/Target/Xtensa/AsmParser/XtensaAsmParser.cpp @@ -55,7 +55,10 @@ OperandMatchResultTy parseRegister(OperandVector &Operands, bool AllowParens = false, bool SR = false); OperandMatchResultTy parseOperandWithModifier(OperandVector &Operands); - bool parseOperand(OperandVector &Operands); + bool parseOperand(OperandVector &Operands, StringRef Mnemonic, + bool SR = false); + bool ParseInstructionWithSR(ParseInstructionInfo &Info, StringRef Name, + SMLoc NameLoc, OperandVector &Operands); OperandMatchResultTy tryParseRegister(MCRegister &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override { return MatchOperand_NoMatch; @@ -141,9 +144,42 @@ bool isImm8_sh8() const { return isImm(-32768, 32512) && - ((dyn_cast(getImm())->getValue() & 0xFF) == 0); + ((cast(getImm())->getValue() & 0xFF) == 0); } + bool isImm12() const { return isImm(-2048, 2047); } + + bool isImm12m() const { return isImm(-2048, 2047); } + + bool isOffset4m32() const { + return isImm(0, 60) && + ((cast(getImm())->getValue() & 0x3) == 0); + } + + bool isOffset8m8() const { return isImm(0, 255); } + + bool isOffset8m16() const { + return isImm(0, 510) && + ((cast(getImm())->getValue() & 0x1) == 0); + } + + bool isOffset8m32() const { + return isImm(0, 1020) && + ((cast(getImm())->getValue() & 0x3) == 0); + } + + bool isUimm4() const { return isImm(0, 15); } + + bool isUimm5() const { return isImm(0, 31); } + + bool isImm8n_7() const { return isImm(-8, 7); } + + bool isShimm1_31() const { return isImm(1, 31); } + + bool isImm16_31() const { return isImm(16, 31); } + + bool isImm1_16() const { return isImm(1, 16); } + /// getStartLoc - Gets location of the first token of this operand SMLoc getStartLoc() const override { return StartLoc; } /// getEndLoc - Gets location of the last token of this operand @@ -292,6 +328,39 @@ return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), "expected immediate in range [-32768, 32512], first 8 bits " "should be zero"); + case Match_InvalidImm12: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-2048, 2047]"); + case Match_InvalidImm12m: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [-2048, 2047]"); + case Match_InvalidImm1_16: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [1, 16]"); + case Match_InvalidShimm1_31: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [1, 31]"); + case Match_InvalidUimm4: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 15]"); + case Match_InvalidUimm5: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 31]"); + case Match_InvalidOffset8m8: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 255]"); + case Match_InvalidOffset8m16: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 510], first bit " + "should be zero"); + case Match_InvalidOffset8m32: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 1020], first 2 bits " + "should be zero"); + case Match_InvalidOffset4m32: + return Error(RefineErrorLoc(IDLoc, Operands, ErrorInfo), + "expected immediate in range [0, 60], first 2 bits " + "should be zero"); } report_fatal_error("Unknown match type detected!"); @@ -324,23 +393,34 @@ if (AllowParens && getLexer().is(AsmToken::LParen)) { size_t ReadCount = getLexer().peekTokens(Buf); if (ReadCount == 2 && Buf[1].getKind() == AsmToken::RParen) { + if ((Buf[0].getKind() == AsmToken::Integer) && (!SR)) + return MatchOperand_NoMatch; HadParens = true; getParser().Lex(); // Eat '(' } } + unsigned RegNo = 0; + switch (getLexer().getKind()) { default: return MatchOperand_NoMatch; + case AsmToken::Integer: + if (!SR) + return MatchOperand_NoMatch; + RegName = StringRef(std::to_string(getLexer().getTok().getIntVal())); + RegNo = MatchRegisterName(RegName); + if (RegNo == 0) + RegNo = MatchRegisterAltName(RegName); + break; case AsmToken::Identifier: RegName = getLexer().getTok().getIdentifier(); + RegNo = MatchRegisterName(RegName); + if (RegNo == 0) + RegNo = MatchRegisterAltName(RegName); break; } - unsigned RegNo = MatchRegisterName(RegName); - if (RegNo == 0) - RegNo = MatchRegisterAltName(RegName); - if (RegNo == 0) { if (HadParens) getLexer().UnLex(Buf[0]); @@ -404,9 +484,10 @@ /// Looks at a token type and creates the relevant operand /// from this information, adding to Operands. /// If operand was parsed, returns false, else true. -bool XtensaAsmParser::parseOperand(OperandVector &Operands) { +bool XtensaAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic, + bool SR) { // Attempt to parse token as register - if (parseRegister(Operands, true) == MatchOperand_Success) + if (parseRegister(Operands, true, SR) == MatchOperand_Success) return false; // Attempt to parse token as an immediate @@ -419,9 +500,75 @@ return true; } +bool XtensaAsmParser::ParseInstructionWithSR(ParseInstructionInfo &Info, + StringRef Name, SMLoc NameLoc, + OperandVector &Operands) { + if ((Name.startswith("wsr.") || Name.startswith("rsr.") || + Name.startswith("xsr.")) && + (Name.size() > 4)) { + // Parse case when instruction name is concatenated with SR register + // name, like "wsr.sar a1" + + // First operand is token for instruction + Operands.push_back(XtensaOperand::createToken(Name.take_front(3), NameLoc)); + + StringRef RegName = Name.drop_front(4); + unsigned RegNo = MatchRegisterName(RegName); + + if (RegNo == 0) + RegNo = MatchRegisterAltName(RegName); + + if (RegNo == 0) { + Error(NameLoc, "invalid register name"); + return true; + } + + // Parse operand + if (parseOperand(Operands, Name)) + return true; + + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + Operands.push_back(XtensaOperand::createReg(RegNo, S, E)); + } else { + // First operand is token for instruction + Operands.push_back(XtensaOperand::createToken(Name, NameLoc)); + + // Parse first operand + if (parseOperand(Operands, Name)) + return true; + + if (!getLexer().is(AsmToken::Comma)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getLexer().Lex(); + + // Parse second operand + if (parseOperand(Operands, Name, true)) + return true; + } + + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + getParser().eatToEndOfStatement(); + return Error(Loc, "unexpected token"); + } + + getParser().Lex(); // Consume the EndOfStatement. + return false; +} + bool XtensaAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { + if (Name.startswith("wsr") || Name.startswith("rsr") || + Name.startswith("xsr")) { + return ParseInstructionWithSR(Info, Name, NameLoc, Operands); + } + // First operand is token for instruction Operands.push_back(XtensaOperand::createToken(Name, NameLoc)); @@ -430,7 +577,7 @@ return false; // Parse first operand - if (parseOperand(Operands)) + if (parseOperand(Operands, Name)) return true; // Parse until end of statement, consuming commas between operands @@ -439,7 +586,7 @@ getLexer().Lex(); // Parse next operand - if (parseOperand(Operands)) + if (parseOperand(Operands, Name)) return true; } diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.h @@ -43,9 +43,20 @@ private: // Print various types of operand. void printOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printMemOperand(const MCInst *MI, int OpNUm, raw_ostream &O); void printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); void printImm8_sh8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm12_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm12m_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printUimm4_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printUimm5_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printImm1_16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); + void printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O); }; } // end namespace llvm diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaInstPrinter.cpp @@ -82,6 +82,13 @@ printOperand(MI->getOperand(OpNum), O); } +void XtensaInstPrinter::printMemOperand(const MCInst *MI, int OpNum, + raw_ostream &OS) { + OS << getRegisterName(MI->getOperand(OpNum).getReg()); + OS << ", "; + printOperand(MI, OpNum + 1, OS); +} + void XtensaInstPrinter::printImm8_AsmOperand(const MCInst *MI, int OpNum, raw_ostream &O) { if (MI->getOperand(OpNum).isImm()) { @@ -105,3 +112,112 @@ } else printOperand(MI, OpNum, O); } + +void XtensaInstPrinter::printImm12_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -2048 && Value <= 2047) && + "Invalid argument, value must be in ranges [-2048,2047]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm12m_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= -2048 && Value <= 2047) && + "Invalid argument, value must be in ranges [-2048,2047]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printUimm4_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 15) && "Invalid argument"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printUimm5_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 31) && "Invalid argument"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printShimm1_31_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 1 && Value <= 31) && + "Invalid argument, value must be in range [1,31]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printImm1_16_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 1 && Value <= 16) && + "Invalid argument, value must be in range [1,16]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m8_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 255) && + "Invalid argument, value must be in range [0,255]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m16_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 510 && ((Value & 0x1) == 0)) && + "Invalid argument, value must be multiples of two in range [0,510]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset8m32_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert( + (Value >= 0 && Value <= 1020 && ((Value & 0x3) == 0)) && + "Invalid argument, value must be multiples of four in range [0,1020]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} + +void XtensaInstPrinter::printOffset4m32_AsmOperand(const MCInst *MI, int OpNum, + raw_ostream &O) { + if (MI->getOperand(OpNum).isImm()) { + int64_t Value = MI->getOperand(OpNum).getImm(); + assert((Value >= 0 && Value <= 60 && ((Value & 0x3) == 0)) && + "Invalid argument, value must be multiples of four in range [0,60]"); + O << Value; + } else + printOperand(MI, OpNum, O); +} diff --git a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp --- a/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp +++ b/llvm/lib/Target/Xtensa/MCTargetDesc/XtensaMCCodeEmitter.cpp @@ -53,6 +53,10 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + uint32_t getMemRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + uint32_t getImm8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; @@ -60,6 +64,26 @@ uint32_t getImm8_sh8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + + uint32_t getImm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getUimm4OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getUimm5OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getImm1_16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + uint32_t getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; }; } // namespace @@ -94,14 +118,48 @@ if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); if (MO.isImm()) { - uint32_t res = static_cast(MO.getImm()); - return res; + uint32_t Res = static_cast(MO.getImm()); + return Res; } report_fatal_error("Unhandled expression!"); return 0; } +uint32_t +XtensaMCCodeEmitter::getMemRegEncoding(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(OpNo + 1).isImm()); + + uint32_t Res = static_cast(MI.getOperand(OpNo + 1).getImm()); + + switch (MI.getOpcode()) { + case Xtensa::S16I: + case Xtensa::L16SI: + case Xtensa::L16UI: + if (Res & 0x1) { + report_fatal_error("Unexpected operand value!"); + } + Res >>= 1; + break; + case Xtensa::S32I: + case Xtensa::L32I: + if (Res & 0x3) { + report_fatal_error("Unexpected operand value!"); + } + Res >>= 2; + break; + } + + assert((isUInt<8>(Res)) && "Unexpected operand value!"); + + uint32_t OffBits = Res << 4; + uint32_t RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI); + + return ((OffBits & 0xFF0) | RegBits); +} + uint32_t XtensaMCCodeEmitter::getImm8OpValue(const MCInst &MI, unsigned OpNo, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -126,4 +184,63 @@ return (Res & 0xffff); } +uint32_t +XtensaMCCodeEmitter::getImm12OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + int32_t Res = MO.getImm(); + + assert(((Res >= -2048) && (Res <= 2047)) && "Unexpected operand value!"); + + return (Res & 0xfff); +} + +uint32_t +XtensaMCCodeEmitter::getUimm4OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert((Res <= 15) && "Unexpected operand value!"); + + return Res & 0xf; +} + +uint32_t +XtensaMCCodeEmitter::getUimm5OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert((Res <= 31) && "Unexpected operand value!"); + + return (Res & 0x1f); +} + +uint32_t +XtensaMCCodeEmitter::getShimm1_31OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert(((Res >= 1) && (Res <= 31)) && "Unexpected operand value!"); + + return ((32 - Res) & 0x1f); +} + +uint32_t +XtensaMCCodeEmitter::getImm1_16OpValue(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + uint32_t Res = static_cast(MO.getImm()); + + assert(((Res >= 1) && (Res <= 16)) && "Unexpected operand value!"); + + return (Res - 1); +} #include "XtensaGenMCCodeEmitter.inc" diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td --- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td +++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td @@ -79,8 +79,16 @@ //===----------------------------------------------------------------------===// // Move instructions //===----------------------------------------------------------------------===// +def MOVI : RRI8_Inst<0x02, (outs AR:$t), (ins imm12m:$imm), + "movi\t$t, $imm", + [(set AR:$t, imm12m:$imm)]> { + bits<12> imm; + + let imm8{7-0} = imm{7-0}; + let s{3-0} = imm{11-8}; + let r = 0xa; +} -// Conditional move def MOVEQZ : RRR_Inst<0x00, 0x03, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), "moveqz\t$r, $s, $t", []>; def MOVNEZ : RRR_Inst<0x00, 0x03, 0x09, (outs AR:$r), (ins AR:$s, AR:$t), @@ -90,9 +98,144 @@ def MOVGEZ : RRR_Inst<0x00, 0x03, 0x0B, (outs AR:$r), (ins AR:$s, AR:$t), "movgez\t$r, $s, $t", []>; +//===----------------------------------------------------------------------===// +// Shift instructions +//===----------------------------------------------------------------------===// + +let Uses = [SAR] in { + def SLL : RRR_Inst<0x00, 0x01, 0x0A, (outs AR:$r), (ins AR:$s), + "sll\t$r, $s", []> { + let t = 0x00; + } + + def SRA : RRR_Inst<0x00, 0x01, 0x0B, (outs AR:$r), (ins AR:$t), + "sra\t$r, $t", []> { + let s = 0x00; + } + + def SRC : RRR_Inst<0x00, 0x01, 0x08, (outs AR:$r), (ins AR:$s, AR:$t), + "src\t$r, $s, $t", []>; + + def SRL : RRR_Inst<0x00, 0x01, 0x09, (outs AR:$r), (ins AR:$t), + "srl\t$r, $t", []> { + let s = 0x00; + } +} + +let Defs = [SAR] in { + def SSL : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssl\t$s", []> { + let r = 0x01; + let t = 0x00; + } + + def SSR : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssr\t$s", []> { + let r = 0x00; + let t = 0x00; + } +} + +def EXTUI : RRR_Inst<0x00, 0x04, 0x00, (outs AR:$r), (ins AR:$t, uimm5:$imm1, imm1_16:$imm2), + "extui\t$r, $t, $imm1, $imm2", []> { + bits<5> imm1; + bits<4> imm2; + + let s = imm1{3-0}; + let Inst{16} = imm1{4}; + let Inst{23-20} = imm2; +} + +def SRAI : RRR_Inst<0x00, 0x01, 0x02, (outs AR:$r), (ins AR:$t, uimm5:$sa), + "srai\t$r, $t, $sa", + [(set AR:$r, (sra AR:$t, uimm5:$sa))]> { + bits<5> sa; + + let Inst{20} = sa{4}; + let s = sa{3-0}; +} + +def SRLI : RRR_Inst<0x00, 0x01, 0x04, (outs AR:$r), (ins AR:$t, uimm4:$sa), + "srli\t$r, $t, $sa", + [(set AR:$r, (srl AR:$t, uimm4:$sa))]> { + bits<4> sa; + + let s = sa; +} + +def SLLI : RRR_Inst<0x00, 0x01, 0x00, (outs AR:$r), (ins AR:$s, shimm1_31:$sa), + "slli\t$r, $s, $sa", + [(set AR:$r, (shl AR:$s, shimm1_31:$sa))]> { + bits<5> sa; + + let Inst{20} = sa{4}; + let t = sa{3-0}; +} + +def SSA8L : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins AR:$s), + "ssa8l\t$s", []> { + let r = 0x2; + let t = 0x0; +} + +def SSAI : RRR_Inst<0x00, 0x00, 0x04, (outs), (ins uimm5:$imm), + "ssai\t$imm", []> { + bits<5> imm; + + let r = 0x04; + let s = imm{3-0}; + let t{3-1} = 0; + let t{0} = imm{4}; +} + +//===----------------------------------------------------------------------===// +// Load and store instructions +//===----------------------------------------------------------------------===// + +// Load instructions +let mayLoad = 1 in { + + class Load_RRI8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp, Operand memOp> + : RRI8_Inst<0x02, (outs AR:$t), (ins memOp:$addr), + instrAsm#"\t$t, $addr", + [(set AR:$t, (opNode addrOp:$addr))]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def L8UI : Load_RRI8<0x00, "l8ui", zextloadi8, addr_ish1, mem8>; +def L16SI : Load_RRI8<0x09, "l16si", sextloadi16, addr_ish2, mem16>; +def L16UI : Load_RRI8<0x01, "l16ui", zextloadi16, addr_ish2, mem16>; +def L32I : Load_RRI8<0x02, "l32i", load, addr_ish4, mem32>; + +// Store instructions +let mayStore = 1 in { + class Store_II8 oper, string instrAsm, SDPatternOperator opNode, + ComplexPattern addrOp, Operand memOp> + : RRI8_Inst<0x02, (outs), (ins AR:$t, memOp:$addr), + instrAsm#"\t$t, $addr", + [(opNode AR:$t, addrOp:$addr)]> { + bits<12> addr; + + let r = oper; + let imm8{7-0} = addr{11-4}; + let s{3-0} = addr{3-0}; + } +} + +def S8I : Store_II8<0x04, "s8i", truncstorei8, addr_ish1, mem8>; +def S16I : Store_II8<0x05, "s16i", truncstorei16, addr_ish2, mem16>; +def S32I : Store_II8<0x06, "s32i", store, addr_ish4, mem32>; + //===----------------------------------------------------------------------===// // Mem barrier instructions //===----------------------------------------------------------------------===// + def MEMW : RRR_Inst<0x00, 0x00, 0x00, (outs), (ins), "memw", []> { let r = 0x2; @@ -150,3 +293,14 @@ let s = 0x00; let t = 0x0f; } + +def WSR : RSR_Inst<0x00, 0x03, 0x01, (outs SR:$sr), (ins AR:$t), + "wsr\t$t, $sr", []>; + +def RSR : RSR_Inst<0x00, 0x03, 0x00, (outs AR:$t), (ins SR:$sr), + "rsr\t$t, $sr", []>; + +def XSR : RSR_Inst<0x00, 0x01, 0x06, (outs AR:$ard, SR:$srd), (ins AR:$t, SR:$sr), + "xsr\t$t, $sr", []> { + let Constraints = "$ard = $t, $srd = $sr"; +} diff --git a/llvm/lib/Target/Xtensa/XtensaOperands.td b/llvm/lib/Target/Xtensa/XtensaOperands.td --- a/llvm/lib/Target/Xtensa/XtensaOperands.td +++ b/llvm/lib/Target/Xtensa/XtensaOperands.td @@ -34,3 +34,86 @@ "Imm8_sh8_AsmOperand"> { let EncoderMethod = "getImm8_sh8OpValue"; } + +// imm12 predicate - Immediate in the range [-2048,2047] +def Imm12_AsmOperand : ImmAsmOperand<"Imm12">; +def imm12 : Immediate= -2048 && Imm <= 2047; }], "Imm12_AsmOperand"> { + let EncoderMethod = "getImm12OpValue"; +} + +// imm12m predicate - Immediate for MOV operation +def Imm12m_AsmOperand : ImmAsmOperand<"Imm12m">; +def imm12m : Immediate= -2048 && Imm <= 2047; }], "Imm12m_AsmOperand"> { + let EncoderMethod = "getImm12OpValue"; +} + +// uimm4 predicate - Immediate in the range [0,15] +def Uimm4_AsmOperand : ImmAsmOperand<"Uimm4">; +def uimm4 : Immediate= 0 && Imm <= 15; }], "Uimm4_AsmOperand"> { + let EncoderMethod = "getUimm4OpValue"; +} + +// uimm5 predicate - Immediate in the range [0,31] +def Uimm5_AsmOperand : ImmAsmOperand<"Uimm5">; +def uimm5 : Immediate= 0 && Imm <= 31; }], "Uimm5_AsmOperand"> { + let EncoderMethod = "getUimm5OpValue"; +} + +// imm1_16 predicate - Immediate in the range [1,16] +def Imm1_16_AsmOperand : ImmAsmOperand<"Imm1_16">; +def imm1_16 : Immediate= 1 && Imm <= 16; }], "Imm1_16_AsmOperand"> { + let EncoderMethod = "getImm1_16OpValue"; +} + +// shimm1_31 predicate - Immediate in the range [1,31] +def Shimm1_31_AsmOperand : ImmAsmOperand<"Shimm1_31">; +def shimm1_31 : Immediate= 1 && Imm <= 31; }], "Shimm1_31_AsmOperand"> { + let EncoderMethod = "getShimm1_31OpValue"; +} + +// Memory offset 0..255 for 8-bit memory accesses +def Offset8m8_AsmOperand : ImmAsmOperand<"Offset8m8">; +def offset8m8 : Immediate= 0 && Imm <= 255; }], + "Offset8m8_AsmOperand">; + +// Memory offset 0..510 for 16-bit memory accesses +def Offset8m16_AsmOperand : ImmAsmOperand<"Offset8m16">; +def offset8m16 : Immediate= 0 && Imm <= 510 && (Imm & 0x1 == 0); }], + "Offset8m16_AsmOperand">; + +// Memory offset 0..1020 for 32-bit memory accesses +def Offset8m32_AsmOperand : ImmAsmOperand<"Offset8m32">; +def offset8m32 : Immediate= 0 && Imm <= 1020 && (Imm & 0x3 == 0); }], + "Offset8m32_AsmOperand">; + +// Memory offset 0..60 for 32-bit memory accesses +def Offset4m32_AsmOperand : ImmAsmOperand<"Offset4m32">; +def offset4m32 : Immediate= 0 && Imm <= 60 && (Imm & 0x3 == 0); }], + "Offset4m32_AsmOperand">; +//===----------------------------------------------------------------------===// +// Memory address operands +//===----------------------------------------------------------------------===// + +class mem : Operand { + let MIOperandInfo = (ops AR, offset); + let EncoderMethod = "getMemRegEncoding"; + let OperandType = "OPERAND_MEMORY"; + let PrintMethod = "printMemOperand"; +} + +def mem8 : mem; + +def mem16 : mem; + +def mem32 : mem; + +def mem32n : mem; + +//Add patterns for future use in stack addressing mode +def addr_ish1 : ComplexPattern; +def addr_ish2 : ComplexPattern; +def addr_ish4 : ComplexPattern; diff --git a/llvm/test/MC/Xtensa/Core/invalid.s b/llvm/test/MC/Xtensa/Core/invalid.s --- a/llvm/test/MC/Xtensa/Core/invalid.s +++ b/llvm/test/MC/Xtensa/Core/invalid.s @@ -1,13 +1,18 @@ # RUN: not llvm-mc -triple xtensa %s 2>&1 | FileCheck %s +LBL0: + # Out of range immediates -LBL0: +# imm12m +movi a1, 3000 +# CHECK: :[[#@LINE-1]]:10: error: expected immediate in range [-2048, 2047] # imm8 addi a1, a2, 300 # CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [-128, 127] +# imm8 addi a1, a2, -129 # CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [-128, 127] @@ -15,6 +20,34 @@ addmi a1, a2, 33 # CHECK: :[[#@LINE-1]]:15: error: expected immediate in range [-32768, 32512], first 8 bits should be zero +# shimm1_31 +slli a1, a2, 0 +# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [1, 31] + +# uimm4 +srli a1, a2, 16 +# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [0, 15] + +# uimm5 +srai a2, a3, 32 +# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [0, 31] + +# imm1_16 +extui a1, a3, 1, 17 +# CHECK: :[[#@LINE-1]]:18: error: expected immediate in range [1, 16] + +# offset8m8 +s8i a1, a2, 300 +# CHECK: :[[#@LINE-1]]:13: error: expected immediate in range [0, 255] + +# offset16m8 +l16si a1, a2, 512 +# CHECK: :[[#@LINE-1]]:15: error: expected immediate in range [0, 510], first bit should be zero + +# offset32m8 +l32i a1, a2, 1024 +# CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [0, 1020], first 2 bits should be zero + # Invalid number of operands addi a1, a2 # CHECK: :[[#@LINE-1]]:1: error: too few operands for instruction @@ -31,7 +64,7 @@ addi sp, a1, a2 # CHECK: :[[#@LINE-1]]:14: error: expected immediate in range [-128, 127] -# Invalid register names +# Check invalid register names for different formats # Instruction format RRR or r2, sp, a3 # CHECK: :[[#@LINE-1]]:4: error: invalid operand for instruction @@ -46,7 +79,17 @@ addi a1, r10, 10 # CHECK: :[[#@LINE-1]]:10: error: invalid operand for instruction -# Invalid operands order +# Instruction format RSR +wsr.uregister a2 +# CHECK: :[[#@LINE-1]]:1: error: invalid register name +wsr a2, uregister +# CHECK: :[[#@LINE-1]]:9: error: invalid operand for instruction + +# Check invalid operands order for different formats # Instruction format RRI8 addi a1, 10, a2 # CHECK: :[[#@LINE-1]]:10: error: invalid operand for instruction + +# Instruction format RSR +wsr sar, a2 +# CHECK: :[[#@LINE-1]]:5: error: invalid operand for instruction diff --git a/llvm/test/MC/Xtensa/Core/memory.s b/llvm/test/MC/Xtensa/Core/memory.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Xtensa/Core/memory.s @@ -0,0 +1,41 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRI8 +# CHECK-INST: l8ui a2, a1, 3 +# CHECK: encoding: [0x22,0x01,0x03] +l8ui a2, sp, 3 + +# Instruction format RRI8 +# CHECK-INST: l16si a3, a1, 4 +# CHECK: encoding: [0x32,0x91,0x02] +l16si a3, sp, 4 + +# Instruction format RRI8 +# CHECK-INST: l16ui a4, a1, 6 +# CHECK: encoding: [0x42,0x11,0x03] +l16ui a4, sp, 6 + +# Instruction format RRI8 +# CHECK-INST: l32i a5, a1, 8 +# CHECK: encoding: [0x52,0x21,0x02] +l32i a5, sp, 8 + +# Instruction format RRI8 +# CHECK-INST: s8i a2, a1, 3 +# CHECK: encoding: [0x22,0x41,0x03] +s8i a2, sp, 3 + +# Instruction format RRI8 +# CHECK-INST: s16i a3, a1, 4 +# CHECK: encoding: [0x32,0x51,0x02] +s16i a3, sp, 4 + +# Instruction format RRI8 +# CHECK-INST: s32i a5, a1, 8 +# CHECK: encoding: [0x52,0x61,0x02] +s32i a5, sp, 8 diff --git a/llvm/test/MC/Xtensa/Core/move.s b/llvm/test/MC/Xtensa/Core/move.s --- a/llvm/test/MC/Xtensa/Core/move.s +++ b/llvm/test/MC/Xtensa/Core/move.s @@ -15,6 +15,11 @@ # CHECK: encoding: [0xc0,0x3b,0xb3] movgez a3, a11, a12 +# Instruction format RRI8 +# CHECK-INST: movi a1, -2048 +# CHECK: encoding: [0x12,0xa8,0x00] +movi a1, -2048 + # Instruction format RRR # CHECK-INST: movltz a7, a8, a9 # CHECK: encoding: [0x90,0x78,0xa3] diff --git a/llvm/test/MC/Xtensa/Core/processor-control.s b/llvm/test/MC/Xtensa/Core/processor-control.s --- a/llvm/test/MC/Xtensa/Core/processor-control.s +++ b/llvm/test/MC/Xtensa/Core/processor-control.s @@ -25,7 +25,46 @@ # CHECK: encoding: [0xf0,0x20,0x00] nop +# Instruction format RSR +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, sar + +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr.sar a8 + +# CHECK-INST: rsr a8, sar +# CHECK: encoding: [0x80,0x03,0x03] +rsr a8, 3 + # Instruction format RRR # CHECK-INST: rsync # CHECK: encoding: [0x10,0x20,0x00] rsync + +# Instruction format RSR +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, sar + +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr.sar a8 + +# CHECK-INST: wsr a8, sar +# CHECK: encoding: [0x80,0x03,0x13] +wsr a8, 3 + +# Instruction format RRR +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr a8, sar + +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr.sar a8 + +# CHECK-INST: xsr a8, sar +# CHECK: encoding: [0x80,0x03,0x61] +xsr a8, 3 diff --git a/llvm/test/MC/Xtensa/Core/shift.s b/llvm/test/MC/Xtensa/Core/shift.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Xtensa/Core/shift.s @@ -0,0 +1,66 @@ +# RUN: llvm-mc %s -triple=xtensa -show-encoding \ +# RUN: | FileCheck -check-prefixes=CHECK,CHECK-INST %s + + +.align 4 +LBL0: + +# Instruction format RRR +# CHECK-INST: extui a1, a2, 7, 8 +# CHECK: encoding: [0x20,0x17,0x74] +extui a1, a2, 7, 8 + +# Instruction format RRR +# CHECK-INST: sll a10, a11 +# CHECK: encoding: [0x00,0xab,0xa1] +sll a10, a11 + +# Instruction format RRR +# CHECK-INST: slli a5, a1, 15 +# CHECK: encoding: [0x10,0x51,0x11] +slli a5, a1, 15 + +# Instruction format RRR +# CHECK-INST: sra a12, a3 +# CHECK: encoding: [0x30,0xc0,0xb1] +sra a12, a3 + +# Instruction format RRR +# CHECK-INST: srai a8, a5, 0 +# CHECK: encoding: [0x50,0x80,0x21] +srai a8, a5, 0 + +# Instruction format RRR +# CHECK-INST: src a3, a4, a5 +# CHECK: encoding: [0x50,0x34,0x81] +src a3, a4, a5 + +# Instruction format RRR +# CHECK-INST: srl a6, a7 +# CHECK: encoding: [0x70,0x60,0x91] +srl a6, a7 + +# Instruction format RRR +# CHECK-INST: srli a3, a4, 8 +# CHECK: encoding: [0x40,0x38,0x41] +srli a3, a4, 8 + +# Instruction format RRR +# CHECK-INST: ssa8l a14 +# CHECK: encoding: [0x00,0x2e,0x40] +ssa8l a14 + +# Instruction format RRR +# CHECK-INST: ssai 31 +# CHECK: encoding: [0x10,0x4f,0x40] +ssai 31 + +# Instruction format RRR +# CHECK-INST: ssl a0 +# CHECK: encoding: [0x00,0x10,0x40] +ssl a0 + +# Instruction format RRR +# CHECK-INST: ssr a2 +# CHECK: encoding: [0x00,0x02,0x40] +ssr a2