diff --git a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp --- a/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp +++ b/llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp @@ -1,4 +1,4 @@ -//===-- CSKYAsmParser.cpp - Parse CSKY assembly to MCInst instructions --===// +//===---- CSKYAsmParser.cpp - Parse CSKY assembly to MCInst instructions --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/CSKYInstPrinter.h" #include "MCTargetDesc/CSKYMCExpr.h" #include "MCTargetDesc/CSKYMCTargetDesc.h" #include "TargetInfo/CSKYTargetInfo.h" @@ -19,10 +20,14 @@ #include "llvm/MC/MCParser/MCParsedAsmOperand.h" #include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionELF.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" + +#define DEBUG_TYPE "csky-asm-parser" using namespace llvm; @@ -31,6 +36,8 @@ class CSKYAsmParser : public MCTargetAsmParser { + const MCRegisterInfo *MRI; + bool generateImmOutOfRangeError(OperandVector &Operands, uint64_t ErrorInfo, int64_t Lower, int64_t Upper, Twine Msg); @@ -51,6 +58,9 @@ OperandMatchResultTy tryParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override; + bool processInstruction(MCInst &Inst, SMLoc IDLoc, OperandVector &Operands, + MCStreamer &Out); + // Auto-generated instruction matching functions #define GET_ASSEMBLER_HEADER #include "CSKYGenAsmMatcher.inc" @@ -60,12 +70,18 @@ OperandMatchResultTy parseBaseRegImm(OperandVector &Operands); OperandMatchResultTy parseCSKYSymbol(OperandVector &Operands); OperandMatchResultTy parseConstpoolSymbol(OperandVector &Operands); + OperandMatchResultTy parseDataSymbol(OperandVector &Operands); + OperandMatchResultTy parsePSRFlag(OperandVector &Operands); + OperandMatchResultTy parseRegSeq(OperandVector &Operands); + OperandMatchResultTy parseRegList(OperandVector &Operands); bool parseOperand(OperandVector &Operands, StringRef Mnemonic); public: enum CSKYMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresSameSrcAndDst, + Match_InvalidRegOutOfRange, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "CSKYGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -80,10 +96,14 @@ /// Instances of this class represent a parsed machine instruction. struct CSKYOperand : public MCParsedAsmOperand { + enum KindTy { Token, Register, Immediate, + RegisterSeq, + CPOP, + RegisterList } Kind; struct RegOp { @@ -94,11 +114,34 @@ const MCExpr *Val; }; + struct ConstpoolOp { + const MCExpr *Val; + }; + + struct RegSeqOp { + unsigned RegNumFrom; + unsigned RegNumTo; + }; + + struct RegListOp { + unsigned List1From = 0; + unsigned List1To = 0; + unsigned List2From = 0; + unsigned List2To = 0; + unsigned List3From = 0; + unsigned List3To = 0; + unsigned List4From = 0; + unsigned List4To = 0; + }; + SMLoc StartLoc, EndLoc; union { StringRef Tok; RegOp Reg; ImmOp Imm; + ConstpoolOp CPool; + RegSeqOp RegSeq; + RegListOp RegList; }; CSKYOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {} @@ -112,18 +155,31 @@ case Register: Reg = o.Reg; break; + case RegisterSeq: + RegSeq = o.RegSeq; + break; + case CPOP: + CPool = o.CPool; + break; case Immediate: Imm = o.Imm; break; case Token: Tok = o.Tok; break; + case RegisterList: + RegList = o.RegList; + break; } } bool isToken() const override { return Kind == Token; } bool isReg() const override { return Kind == Register; } bool isImm() const override { return Kind == Immediate; } + bool isRegisterSeq() const { return Kind == RegisterSeq; } + bool isRegisterList() const { return Kind == RegisterList; } + bool isConstPoolOp() const { return Kind == CPOP; } + bool isMem() const override { return false; } static bool evaluateConstantImm(const MCExpr *Expr, int64_t &Imm) { @@ -162,29 +218,132 @@ return IsConstantImm && isShiftedInt(Imm); } + bool isUImm1() const { return isUImm<1>(); } bool isUImm2() const { return isUImm<2>(); } + bool isUImm3() const { return isUImm<3>(); } + bool isUImm4() const { return isUImm<4>(); } bool isUImm5() const { return isUImm<5>(); } + bool isUImm6() const { return isUImm<6>(); } + bool isUImm7() const { return isUImm<7>(); } + bool isUImm8() const { return isUImm<8>(); } bool isUImm12() const { return isUImm<12>(); } bool isUImm16() const { return isUImm<16>(); } - + bool isUImm20() const { return isUImm<20>(); } + bool isUImm24() const { return isUImm<24>(); } + + bool isOImm3() const { return isOImm<3>(); } + bool isOImm4() const { return isOImm<4>(); } + bool isOImm5() const { return isOImm<5>(); } + bool isOImm6() const { return isOImm<6>(); } + bool isOImm8() const { return isOImm<8>(); } bool isOImm12() const { return isOImm<12>(); } bool isOImm16() const { return isOImm<16>(); } + bool isSImm8() const { return isSImm<8>(); } + + bool isUImm5Shift1() { return isUImm<5, 1>(); } + bool isUImm5Shift2() { return isUImm<5, 2>(); } + bool isUImm7Shift1() { return isUImm<7, 1>(); } + bool isUImm7Shift2() { return isUImm<7, 2>(); } + bool isUImm7Shift3() { return isUImm<7, 3>(); } + bool isUImm8Shift2() { return isUImm<8, 2>(); } + bool isUImm8Shift3() { return isUImm<8, 3>(); } + bool isUImm8Shift8() { return isUImm<8, 8>(); } + bool isUImm8Shift16() { return isUImm<8, 16>(); } + bool isUImm8Shift24() { return isUImm<8, 24>(); } bool isUImm12Shift1() { return isUImm<12, 1>(); } bool isUImm12Shift2() { return isUImm<12, 2>(); } + bool isUImm16Shift8() { return isUImm<16, 8>(); } + bool isUImm16Shift16() { return isUImm<16, 16>(); } + bool isUImm24Shift8() { return isUImm<24, 8>(); } bool isSImm16Shift1() { return isSImm<16, 1>(); } - bool isCSKYSymbol() const { + bool isCSKYSymbol() const { return isImm(); } + + bool isConstpool() const { return isConstPoolOp(); } + bool isDataSymbol() const { return isConstPoolOp(); } + + bool isSPOperand() const { + if (!isReg()) + return false; + return getReg() == CSKY::R14; + } + + bool isPSRFlag() const { int64_t Imm; - // Must be of 'immediate' type but not a constant. - return isImm() && !evaluateConstantImm(getImm(), Imm); + // Must be of 'immediate' type and a constant. + if (!isImm() || !evaluateConstantImm(getImm(), Imm)) + return false; + + return isUInt<5>(Imm); } - bool isConstpoolSymbol() const { + template bool isRegSeqTemplate() const { + if (!isRegisterSeq()) + return false; + + std::pair regSeq = getRegSeq(); + + return MIN <= regSeq.first && regSeq.first <= regSeq.second && + regSeq.second <= MAX; + } + + bool isRegSeq() const { return isRegSeqTemplate(); } + + static bool isLegalRegList(unsigned from, unsigned to) { + if (from == 0 && to == 0) + return true; + + if (from == to) { + if (from != CSKY::R4 && from != CSKY::R15 && from != CSKY::R16 && + from != CSKY::R28) + return false; + + return true; + } else { + if (from != CSKY::R4 && from != CSKY::R16) + return false; + + if (from == CSKY::R4 && to > CSKY::R4 && to < CSKY::R12) + return true; + else if (from == CSKY::R16 && to > CSKY::R16 && to < CSKY::R18) + return true; + else + return false; + } + } + + bool isRegList() const { + if (!isRegisterList()) + return false; + + auto regList = getRegList(); + + if (!isLegalRegList(regList.List1From, regList.List1To)) + return false; + if (!isLegalRegList(regList.List2From, regList.List2To)) + return false; + if (!isLegalRegList(regList.List3From, regList.List3To)) + return false; + if (!isLegalRegList(regList.List4From, regList.List4To)) + return false; + + return true; + } + + bool isExtImm6() { + if (!isImm()) + return false; + int64_t Imm; - // Must be of 'immediate' type but not a constant. - return isImm() && !evaluateConstantImm(getImm(), Imm); + bool IsConstantImm = evaluateConstantImm(getImm(), Imm); + if (!IsConstantImm) + return false; + + int uimm4 = Imm & 0xf; + + return isShiftedUInt<6, 0>(Imm) && uimm4 >= 0 && uimm4 <= 14; } /// Gets location of the first token of this operand. @@ -197,23 +356,64 @@ return Reg.RegNum; } + std::pair getRegSeq() const { + assert(Kind == RegisterSeq && "Invalid type access!"); + return std::pair(RegSeq.RegNumFrom, RegSeq.RegNumTo); + } + + RegListOp getRegList() const { + assert(Kind == RegisterList && "Invalid type access!"); + return RegList; + } + const MCExpr *getImm() const { assert(Kind == Immediate && "Invalid type access!"); return Imm.Val; } + const MCExpr *getConstpoolOp() const { + assert(Kind == CPOP && "Invalid type access!"); + return CPool.Val; + } + StringRef getToken() const { assert(Kind == Token && "Invalid type access!"); return Tok; } void print(raw_ostream &OS) const override { + auto RegName = [](unsigned Reg) { + if (Reg) + return CSKYInstPrinter::getRegisterName(Reg); + else + return "noreg"; + }; + switch (Kind) { + case CPOP: + OS << *getConstpoolOp(); + break; case Immediate: OS << *getImm(); break; - case Register: - OS << ""; + case KindTy::Register: + OS << ""; + break; + case RegisterSeq: + OS << ""; + break; + case RegisterList: + OS << " createRegSeq(unsigned RegNoFrom, + unsigned RegNoTo, SMLoc S) { + auto Op = std::make_unique(RegisterSeq); + Op->RegSeq.RegNumFrom = RegNoFrom; + Op->RegSeq.RegNumTo = RegNoTo; + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + + static std::unique_ptr + createRegList(SmallVector reglist, SMLoc S) { + auto Op = std::make_unique(RegisterList); + Op->RegList.List1From = 0; + Op->RegList.List1To = 0; + Op->RegList.List2From = 0; + Op->RegList.List2To = 0; + Op->RegList.List3From = 0; + Op->RegList.List3To = 0; + Op->RegList.List4From = 0; + Op->RegList.List4To = 0; + + for (unsigned i = 0; i < reglist.size(); i += 2) { + if (Op->RegList.List1From == 0) { + Op->RegList.List1From = reglist[i]; + Op->RegList.List1To = reglist[i + 1]; + } else if (Op->RegList.List2From == 0) { + Op->RegList.List2From = reglist[i]; + Op->RegList.List2To = reglist[i + 1]; + } else if (Op->RegList.List3From == 0) { + Op->RegList.List3From = reglist[i]; + Op->RegList.List3To = reglist[i + 1]; + } else if (Op->RegList.List4From == 0) { + Op->RegList.List4From = reglist[i]; + Op->RegList.List4To = reglist[i + 1]; + } else { + assert(0); + } + } + + Op->StartLoc = S; + Op->EndLoc = S; + return Op; + } + static std::unique_ptr createImm(const MCExpr *Val, SMLoc S, SMLoc E) { auto Op = std::make_unique(Immediate); @@ -247,6 +492,15 @@ return Op; } + static std::unique_ptr createConstpoolOp(const MCExpr *Val, + SMLoc S, SMLoc E) { + auto Op = std::make_unique(CPOP); + Op->CPool.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; + } + void addExpr(MCInst &Inst, const MCExpr *Expr) const { assert(Expr && "Expr shouldn't be null!"); if (auto *CE = dyn_cast(Expr)) @@ -265,6 +519,70 @@ assert(N == 1 && "Invalid number of operands!"); addExpr(Inst, getImm()); } + + void addConstpoolOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createExpr(getConstpoolOp())); + } + + void addRegSeqOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + auto regSeq = getRegSeq(); + + Inst.addOperand(MCOperand::createReg(regSeq.first)); + Inst.addOperand(MCOperand::createReg(regSeq.second)); + } + + static unsigned getListValue(unsigned ListFrom, unsigned ListTo) { + if (ListFrom == ListTo && ListFrom == CSKY::R15) + return (1 << 4); + else if (ListFrom == ListTo && ListFrom == CSKY::R28) + return (1 << 8); + else if (ListFrom == CSKY::R4) + return ListTo - ListFrom + 1; + else if (ListFrom == CSKY::R16) + return ((ListTo - ListFrom + 1) << 5); + else + return 0; + } + + void addRegListOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + auto regList = getRegList(); + + unsigned V = 0; + + unsigned T = getListValue(regList.List1From, regList.List1To); + if (T != 0) + V = V | T; + + T = getListValue(regList.List2From, regList.List2To); + if (T != 0) + V = V | T; + + T = getListValue(regList.List3From, regList.List3To); + if (T != 0) + V = V | T; + + T = getListValue(regList.List4From, regList.List4To); + if (T != 0) + V = V | T; + + Inst.addOperand(MCOperand::createImm(V)); + } + + bool isValidForTie(const CSKYOperand &Other) const { + if (Kind != Other.Kind) + return false; + + switch (Kind) { + default: + llvm_unreachable("Unexpected kind"); + return false; + case Register: + return Reg.RegNum == Other.Reg.RegNum; + } + } }; } // end anonymous namespace. @@ -298,9 +616,7 @@ default: break; case Match_Success: - Inst.setLoc(IDLoc); - Out.emitInstruction(Inst, getSTI()); - return false; + return processInstruction(Inst, IDLoc, Operands, Out); case Match_MissingFeature: { assert(MissingFeatures.any() && "Unknown missing features!"); ListSeparator LS; @@ -346,26 +662,79 @@ switch (Result) { default: break; + case Match_InvalidSImm8: + return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 7), + (1 << 7) - 1); + case Match_InvalidOImm3: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 3)); + case Match_InvalidOImm4: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 4)); + case Match_InvalidOImm5: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 5)); + case Match_InvalidOImm6: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 6)); + case Match_InvalidOImm8: + return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 8)); case Match_InvalidOImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 12)); case Match_InvalidOImm16: return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 16)); + case Match_InvalidUImm1: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 1) - 1); case Match_InvalidUImm2: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 2) - 1); + case Match_InvalidUImm3: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 3) - 1); + case Match_InvalidUImm4: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 4) - 1); case Match_InvalidUImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1); + case Match_InvalidUImm6: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 6) - 1); + case Match_InvalidUImm7: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 7) - 1); + case Match_InvalidUImm8: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 8) - 1); case Match_InvalidUImm12: return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1); + case Match_InvalidUImm16: + return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1); + case Match_InvalidUImm5Shift1: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 5) - 2, + "immediate must be a multiple of 2 bytes in the range"); case Match_InvalidUImm12Shift1: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 12) - 2, "immediate must be a multiple of 2 bytes in the range"); + case Match_InvalidUImm5Shift2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 5) - 4, + "immediate must be a multiple of 4 bytes in the range"); + case Match_InvalidUImm7Shift1: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 7) - 2, + "immediate must be a multiple of 2 bytes in the range"); + case Match_InvalidUImm7Shift2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 7) - 4, + "immediate must be a multiple of 4 bytes in the range"); + case Match_InvalidUImm8Shift2: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 8) - 4, + "immediate must be a multiple of 4 bytes in the range"); + case Match_InvalidUImm8Shift3: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 8) - 8, + "immediate must be a multiple of 8 bytes in the range"); + case Match_InvalidUImm8Shift8: + return generateImmOutOfRangeError( + Operands, ErrorInfo, 0, (1 << 8) - 256, + "immediate must be a multiple of 256 bytes in the range"); case Match_InvalidUImm12Shift2: return generateImmOutOfRangeError( Operands, ErrorInfo, 0, (1 << 12) - 4, "immediate must be a multiple of 4 bytes in the range"); - case Match_InvalidUImm16: - return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1); case Match_InvalidCSKYSymbol: { SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a symbol name"); @@ -374,15 +743,64 @@ SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); return Error(ErrorLoc, "operand must be a constpool symbol name"); } + case Match_InvalidPSRFlag: { + SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "psrset operand is not valid"); + } + case Match_InvalidRegSeq: { + SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "Register sequence is not valid"); } - + case Match_InvalidRegOutOfRange: { + SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "register is out of range"); + } + case Match_RequiresSameSrcAndDst: { + SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "src and dst operand must be same"); + } + case Match_InvalidRegList: { + SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc(); + return Error(ErrorLoc, "invalid register list"); + } + } + LLVM_DEBUG(dbgs() << "Result = " << Result); llvm_unreachable("Unknown match type detected!"); } +bool CSKYAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc, + OperandVector &Operands, + MCStreamer &Out) { + + if (Inst.getOpcode() == CSKY::LDQ32 || Inst.getOpcode() == CSKY::STQ32) { + if (Inst.getOperand(1).getReg() != CSKY::R4 || + Inst.getOperand(2).getReg() != CSKY::R7) { + return Error(IDLoc, "Register sequence is not valid. 'r4-r7' expected"); + } + Inst.setOpcode(Inst.getOpcode() == CSKY::LDQ32 ? CSKY::LDM32 : CSKY::STM32); + Out.emitInstruction(Inst, getSTI()); + return false; + } else if (Inst.getOpcode() == CSKY::SEXT32 || + Inst.getOpcode() == CSKY::ZEXT32) { + if (Inst.getOperand(2).getImm() < Inst.getOperand(3).getImm()) + return Error(IDLoc, "msb must be greater or equal to lsb"); + } else if (Inst.getOpcode() == CSKY::INS32) { + if (Inst.getOperand(3).getImm() < Inst.getOperand(4).getImm()) + return Error(IDLoc, "msb must be greater or equal to lsb"); + } else if (Inst.getOpcode() == CSKY::IDLY32) { + if (Inst.getOperand(0).getImm() > 32 || Inst.getOperand(0).getImm() < 0) + return Error(IDLoc, "n must be in range [0,32]"); + } + + Out.emitInstruction(Inst, getSTI()); + return false; +} + // Attempts to match Name as a register (either using the default name or // alternative ABI names), setting RegNo to the matching register. Upon // failure, returns true and sets RegNo to 0. -static bool matchRegisterNameHelper(MCRegister &RegNo, StringRef Name) { +static bool matchRegisterNameHelper(const MCSubtargetInfo &STI, + MCRegister &RegNo, StringRef Name) { RegNo = MatchRegisterName(Name); if (RegNo == CSKY::NoRegister) @@ -398,12 +816,12 @@ EndLoc = Tok.getEndLoc(); StringRef Name = getLexer().getTok().getIdentifier(); - if (!matchRegisterNameHelper((MCRegister &)RegNo, Name)) { + if (!matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) { getParser().Lex(); // Eat identifier token. return false; } - return Error(StartLoc, "invalid register name"); + return MatchOperand_NoMatch; } OperandMatchResultTy CSKYAsmParser::parseRegister(OperandVector &Operands) { @@ -417,7 +835,7 @@ StringRef Name = getLexer().getTok().getIdentifier(); MCRegister RegNo; - if (matchRegisterNameHelper((MCRegister &)RegNo, Name)) + if (matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) return MatchOperand_NoMatch; getLexer().Lex(); @@ -438,7 +856,13 @@ if (parseRegister(Operands) != MatchOperand_Success) { getLexer().UnLex(Tok); Operands.pop_back(); - return MatchOperand_ParseFail; + return MatchOperand_NoMatch; + } + + if (getLexer().is(AsmToken::RParen)) { + Operands.push_back(CSKYOperand::createToken(")", getLoc())); + getParser().Lex(); // Eat ')' + return MatchOperand_Success; } if (getLexer().isNot(AsmToken::Comma)) { @@ -494,8 +918,10 @@ const MCExpr *IdVal; SMLoc S = getLoc(); - if (getParser().parseExpression(IdVal)) + if (getParser().parseExpression(IdVal)) { + Error(getLoc(), "unknown expression"); return MatchOperand_ParseFail; + } SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); Operands.push_back(CSKYOperand::createImm(IdVal, S, E)); @@ -516,17 +942,26 @@ return true; // Attempt to parse token as register - if (parseRegister(Operands) == MatchOperand_Success) + auto Res = parseRegister(Operands); + if (Res == MatchOperand_Success) return false; + else if (Res == MatchOperand_ParseFail) + return true; // Attempt to parse token as (register, imm) - if (getLexer().is(AsmToken::LParen)) - if (parseBaseRegImm(Operands) == MatchOperand_Success) + if (getLexer().is(AsmToken::LParen)) { + Res = parseBaseRegImm(Operands); + if (Res == MatchOperand_Success) return false; + else if (Res == MatchOperand_ParseFail) + return true; + } - // Attempt to parse token as a imm. - if (parseImmediate(Operands) == MatchOperand_Success) + Res = parseImmediate(Operands); + if (Res == MatchOperand_Success) return false; + else if (Res == MatchOperand_ParseFail) + return true; // Finally we have exhausted all options and must declare defeat. Error(getLoc(), "unknown operand"); @@ -536,16 +971,20 @@ OperandMatchResultTy CSKYAsmParser::parseCSKYSymbol(OperandVector &Operands) { SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; if (getLexer().getKind() != AsmToken::Identifier) return MatchOperand_NoMatch; StringRef Identifier; - if (getParser().parseIdentifier(Identifier)) + AsmToken Tok = getLexer().getTok(); + + if (getParser().parseIdentifier(Identifier)) { + Error(getLoc(), "unknown identifier"); return MatchOperand_ParseFail; + } CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None; - if (Identifier.consume_back("@GOT")) Kind = CSKYMCExpr::VK_CSKY_GOT; else if (Identifier.consume_back("@GOTOFF")) @@ -554,44 +993,377 @@ Kind = CSKYMCExpr::VK_CSKY_PLT; else if (Identifier.consume_back("@GOTPC")) Kind = CSKYMCExpr::VK_CSKY_GOTPC; + else if (Identifier.consume_back("@TLSGD32")) + Kind = CSKYMCExpr::VK_CSKY_TLSGD; + else if (Identifier.consume_back("@GOTTPOFF")) + Kind = CSKYMCExpr::VK_CSKY_TLSIE; + else if (Identifier.consume_back("@TPOFF")) + Kind = CSKYMCExpr::VK_CSKY_TLSLE; + else if (Identifier.consume_back("@TLSLDM32")) + Kind = CSKYMCExpr::VK_CSKY_TLSLDM; + else if (Identifier.consume_back("@TLSLDO32")) + Kind = CSKYMCExpr::VK_CSKY_TLSLDO; + + MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); + + if (!Sym) + Sym = getContext().getOrCreateSymbol(Identifier); + + if (Sym->isVariable()) { + const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); + if (!isa(V)) { + getLexer().UnLex(Tok); // Put back if it's not a bare symbol. + Error(getLoc(), "unknown symbol"); + return MatchOperand_ParseFail; + } + Res = V; + } else + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - const MCExpr *Res = - MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + MCBinaryExpr::Opcode Opcode; + switch (getLexer().getKind()) { + default: + if (Kind != CSKYMCExpr::VK_CSKY_None) + Res = CSKYMCExpr::create(Res, Kind, getContext()); - if (Kind != CSKYMCExpr::VK_CSKY_None) - Res = CSKYMCExpr::create(Res, Kind, getContext()); + Operands.push_back(CSKYOperand::createImm(Res, S, E)); + return MatchOperand_Success; + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + break; + } + + getLexer().Lex(); // eat + or - + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(getLoc(), "unknown expression"); + return MatchOperand_ParseFail; + } + Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); Operands.push_back(CSKYOperand::createImm(Res, S, E)); return MatchOperand_Success; } +OperandMatchResultTy CSKYAsmParser::parseDataSymbol(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; + + if (getLexer().getKind() != AsmToken::LBrac) + return MatchOperand_NoMatch; + + getLexer().Lex(); // Eat '['. + + if (getLexer().getKind() != AsmToken::Identifier) { + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(getLoc(), "unknown expression"); + return MatchOperand_ParseFail; + } + + if (getLexer().getKind() != AsmToken::RBrac) { + Error(getLoc(), "expected ]"); + return MatchOperand_ParseFail; + } + + getLexer().Lex(); // Eat ']'. + + Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); + return MatchOperand_Success; + } + + AsmToken Tok = getLexer().getTok(); + StringRef Identifier; + + if (getParser().parseIdentifier(Identifier)) { + Error(getLoc(), "unknown identifier " + Identifier); + return MatchOperand_ParseFail; + } + + CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None; + if (Identifier.consume_back("@GOT")) + Kind = CSKYMCExpr::VK_CSKY_GOT_IMM18_BY4; + else if (Identifier.consume_back("@PLT")) + Kind = CSKYMCExpr::VK_CSKY_PLT_IMM18_BY4; + + MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); + + if (!Sym) + Sym = getContext().getOrCreateSymbol(Identifier); + + if (Sym->isVariable()) { + const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); + if (!isa(V)) { + getLexer().UnLex(Tok); // Put back if it's not a bare symbol. + Error(getLoc(), "unknown symbol"); + return MatchOperand_ParseFail; + } + Res = V; + } else { + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + } + + MCBinaryExpr::Opcode Opcode; + switch (getLexer().getKind()) { + default: + Error(getLoc(), "unknown symbol"); + return MatchOperand_ParseFail; + case AsmToken::RBrac: + + getLexer().Lex(); // Eat ']'. + + if (Kind != CSKYMCExpr::VK_CSKY_None) + Res = CSKYMCExpr::create(Res, Kind, getContext()); + + Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); + return MatchOperand_Success; + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + break; + } + + getLexer().Lex(); // eat + or - + + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(getLoc(), "unknown expression"); + return MatchOperand_ParseFail; + } + + if (getLexer().getKind() != AsmToken::RBrac) { + Error(getLoc(), "expected ']'"); + return MatchOperand_ParseFail; + } + + getLexer().Lex(); // Eat ']'. + + Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); + Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); + return MatchOperand_Success; +} + OperandMatchResultTy CSKYAsmParser::parseConstpoolSymbol(OperandVector &Operands) { SMLoc S = getLoc(); SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + const MCExpr *Res; if (getLexer().getKind() != AsmToken::LBrac) return MatchOperand_NoMatch; getLexer().Lex(); // Eat '['. - if (getLexer().getKind() != AsmToken::Identifier) - return MatchOperand_NoMatch; + if (getLexer().getKind() != AsmToken::Identifier) { + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(getLoc(), "unknown expression"); + return MatchOperand_ParseFail; + } + + if (getLexer().getKind() != AsmToken::RBrac) { + Error(getLoc(), "expected ']'"); + return MatchOperand_ParseFail; + } + + getLexer().Lex(); // Eat ']'. + Operands.push_back(CSKYOperand::createConstpoolOp(Expr, S, E)); + return MatchOperand_Success; + } + + AsmToken Tok = getLexer().getTok(); StringRef Identifier; - if (getParser().parseIdentifier(Identifier)) + + if (getParser().parseIdentifier(Identifier)) { + Error(getLoc(), "unknown identifier"); return MatchOperand_ParseFail; + } - if (getLexer().getKind() != AsmToken::RBrac) - return MatchOperand_NoMatch; + MCSymbol *Sym = getContext().getInlineAsmLabel(Identifier); + + if (!Sym) + Sym = getContext().getOrCreateSymbol(Identifier); + + if (Sym->isVariable()) { + const MCExpr *V = Sym->getVariableValue(/*SetUsed=*/false); + if (!isa(V)) { + getLexer().UnLex(Tok); // Put back if it's not a bare symbol. + Error(getLoc(), "unknown symbol"); + return MatchOperand_ParseFail; + } + Res = V; + } else { + Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); + } + + MCBinaryExpr::Opcode Opcode; + switch (getLexer().getKind()) { + default: + Error(getLoc(), "unknown symbol"); + return MatchOperand_ParseFail; + case AsmToken::RBrac: + + getLexer().Lex(); // Eat ']'. + + Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); + return MatchOperand_Success; + case AsmToken::Plus: + Opcode = MCBinaryExpr::Add; + break; + case AsmToken::Minus: + Opcode = MCBinaryExpr::Sub; + break; + } + + getLexer().Lex(); // eat + or - + + const MCExpr *Expr; + if (getParser().parseExpression(Expr)) { + Error(getLoc(), "unknown expression"); + return MatchOperand_ParseFail; + } + + if (getLexer().getKind() != AsmToken::RBrac) { + Error(getLoc(), "expected ']'"); + return MatchOperand_ParseFail; + } getLexer().Lex(); // Eat ']'. - MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier); - const MCExpr *Res = - MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - Operands.push_back(CSKYOperand::createImm(Res, S, E)); + Res = MCBinaryExpr::create(Opcode, Res, Expr, getContext()); + Operands.push_back(CSKYOperand::createConstpoolOp(Res, S, E)); + return MatchOperand_Success; +} + +OperandMatchResultTy CSKYAsmParser::parsePSRFlag(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1); + + unsigned Flag = 0; + + while (getLexer().isNot(AsmToken::EndOfStatement)) { + StringRef Identifier; + if (getParser().parseIdentifier(Identifier)) { + Error(getLoc(), "unknown identifier " + Identifier); + return MatchOperand_ParseFail; + } + + if (Identifier == "sie") + Flag = (1 << 4) | Flag; + else if (Identifier == "ee") + Flag = (1 << 3) | Flag; + else if (Identifier == "ie") + Flag = (1 << 2) | Flag; + else if (Identifier == "fe") + Flag = (1 << 1) | Flag; + else if (Identifier == "af") + Flag = (1 << 0) | Flag; + else { + Error(getLoc(), "expected " + Identifier); + return MatchOperand_ParseFail; + } + + if (getLexer().is(AsmToken::EndOfStatement)) + break; + + if (getLexer().is(AsmToken::Comma)) { + getLexer().Lex(); // eat ',' + } else { + Error(getLoc(), "expected ,"); + return MatchOperand_ParseFail; + } + } + + Operands.push_back( + CSKYOperand::createImm(MCConstantExpr::create(Flag, getContext()), S, E)); + return MatchOperand_Success; +} + +OperandMatchResultTy CSKYAsmParser::parseRegSeq(OperandVector &Operands) { + SMLoc S = getLoc(); + + if (parseRegister(Operands) != MatchOperand_Success) + return MatchOperand_NoMatch; + + auto Ry = Operands.back()->getReg(); + Operands.pop_back(); + + if (getLexer().isNot(AsmToken::Minus)) { + Error(getLoc(), "expected '-'"); + return MatchOperand_ParseFail; + } + + getLexer().Lex(); // eat '-' + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "invalid register"); + return MatchOperand_ParseFail; + } + + auto Rz = Operands.back()->getReg(); + Operands.pop_back(); + + Operands.push_back(CSKYOperand::createRegSeq(Ry, Rz, S)); + return MatchOperand_Success; +} + +OperandMatchResultTy CSKYAsmParser::parseRegList(OperandVector &Operands) { + SMLoc S = getLoc(); + + SmallVector reglist; + + while (true) { + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "invalid register"); + return MatchOperand_ParseFail; + } + + auto Ry = Operands.back()->getReg(); + Operands.pop_back(); + + if (getLexer().is(AsmToken::Minus)) { + getLexer().Lex(); // eat '-' + + if (parseRegister(Operands) != MatchOperand_Success) { + Error(getLoc(), "invalid register"); + return MatchOperand_ParseFail; + } + + auto Rz = Operands.back()->getReg(); + Operands.pop_back(); + + reglist.push_back(Ry); + reglist.push_back(Rz); + + if (getLexer().is(AsmToken::Comma)) + getLexer().Lex(); // eat ',' + else if (getLexer().is(AsmToken::EndOfStatement)) + break; + + } else if (getLexer().is(AsmToken::Comma)) { + reglist.push_back(Ry); + reglist.push_back(Ry); + + getLexer().Lex(); // eat ',' + } else if (getLexer().is(AsmToken::EndOfStatement)) { + reglist.push_back(Ry); + reglist.push_back(Ry); + break; + } else { + Error(getLoc(), "invalid register list"); + return MatchOperand_ParseFail; + } + } + + Operands.push_back(CSKYOperand::createRegList(reglist, S)); return MatchOperand_Success; } @@ -637,7 +1409,7 @@ StringRef Name = getLexer().getTok().getIdentifier(); - if (matchRegisterNameHelper((MCRegister &)RegNo, Name)) + if (matchRegisterNameHelper(getSTI(), (MCRegister &)RegNo, Name)) return MatchOperand_NoMatch; getParser().Lex(); // Eat identifier token. @@ -648,4 +1420,4 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYAsmParser() { RegisterMCAsmParser X(getTheCSKYTarget()); -} +} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CMakeLists.txt b/llvm/lib/Target/CSKY/CMakeLists.txt --- a/llvm/lib/Target/CSKY/CMakeLists.txt +++ b/llvm/lib/Target/CSKY/CMakeLists.txt @@ -12,6 +12,7 @@ add_public_tablegen_target(CSKYCommonTableGen) add_llvm_target(CSKYCodeGen + CSKYSubtarget.cpp CSKYTargetMachine.cpp LINK_COMPONENTS diff --git a/llvm/lib/Target/CSKY/CSKY.td b/llvm/lib/Target/CSKY/CSKY.td --- a/llvm/lib/Target/CSKY/CSKY.td +++ b/llvm/lib/Target/CSKY/CSKY.td @@ -8,6 +8,80 @@ include "llvm/Target/Target.td" +//===----------------------------------------------------------------------===// +// CSKY subtarget features and instruction predicates. +//===----------------------------------------------------------------------===// + +// Atomic Support +def FeatureExtendLrw : SubtargetFeature<"elrw", "HasExtendLrw", "true", + "Use the extend LRW instruction">; +def HasExtendLrw : Predicate<"Subtarget->hasExtendLrw()">, + AssemblerPredicate<(all_of FeatureExtendLrw), + "Use the extend LRW instruction">; + +def FeatureDoloop : SubtargetFeature<"doloop", "HasDoloop", "true", + "Enable doloop instructions">; +def HasDoloop : Predicate<"Subtarget->hasDoloop()">, + AssemblerPredicate<(all_of FeatureDoloop), + "Enable doloop instructions">; + +def HasE1 + : SubtargetFeature<"e1", "HasE1", "true", "Support CSKY e1 instructions", + [FeatureExtendLrw]>; +def iHasE1 : Predicate<"Subtarget->hasE1()">, + AssemblerPredicate<(all_of HasE1), + "Support CSKY e1 instructions">; + +def HasE2 + : SubtargetFeature<"e2", "HasE2", "true", "Support CSKY e2 instructions", + [HasE1]>; +def iHasE2 : Predicate<"Subtarget->hasE2()">, + AssemblerPredicate<(all_of HasE2), + "Support CSKY e2 instructions">; + +def Has2E3 : SubtargetFeature<"2e3", "Has2E3", "true", + "Support CSKY 2e3 instructions", [HasE2]>; +def iHas2E3 : Predicate<"Subtarget->has2E3()">, + AssemblerPredicate<(all_of Has2E3), + "Support CSKY 2e3 instructions">; + +def Has3E3r1 : SubtargetFeature<"3e3r1", "Has3E3r1", "true", + "Support CSKY 3e3r1 instructions">; +def iHas3E3r1 : Predicate<"Subtarget->has3E3r1()">, + AssemblerPredicate<(all_of Has3E3r1), + "Support CSKY 3e3r1 instructions">; + +def Has3r2E3r3 + : SubtargetFeature<"3e3r3", "Has3r2E3r3", "true", + "Support CSKY 3e3r3 instructions", [FeatureDoloop]>; +def iHas3r2E3r3 : Predicate<"Subtarget->has3r2E3r3()">, + AssemblerPredicate<(all_of Has3r2E3r3), + "Support CSKY 3e3r3 instructions">; + +def Has3E7 : SubtargetFeature<"3e7", "Has3E7", "true", + "Support CSKY 3e7 instructions", [Has2E3]>; +def iHas3E7 : Predicate<"Subtarget->has3E7()">, + AssemblerPredicate<(all_of Has3E7), + "Support CSKY 3e7 instructions">; + +def HasMP1E2 : SubtargetFeature<"mp1e2", "HasMP1E2", "true", + "Support CSKY mp1e2 instructions", [Has3E7]>; +def iHasMP1E2 : Predicate<"Subtarget->hasMP1E2()">, + AssemblerPredicate<(all_of HasMP1E2), + "Support CSKY mp1e2 instructions">; + +def Has7E10 : SubtargetFeature<"7e10", "Has7E10", "true", + "Support CSKY 7e10 instructions", [Has3E7]>; +def iHas7E10 : Predicate<"Subtarget->has7E10()">, + AssemblerPredicate<(all_of Has7E10), + "Support CSKY 7e10 instructions">; + +def Has10E60 : SubtargetFeature<"10e60", "Has10E60", "true", + "Support CSKY 10e60 instructions", [Has7E10]>; +def iHas10E60 : Predicate<"Subtarget->has10E60()">, + AssemblerPredicate<(all_of Has10E60), + "Support CSKY 10e60 instructions">; + //===----------------------------------------------------------------------===// // Registers, calling conventions, instruction descriptions. //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/CSKY/CSKYInstrFormats.td b/llvm/lib/Target/CSKY/CSKYInstrFormats.td --- a/llvm/lib/Target/CSKY/CSKYInstrFormats.td +++ b/llvm/lib/Target/CSKY/CSKYInstrFormats.td @@ -24,7 +24,7 @@ let Namespace = "CSKY"; int Size = sz; AddrMode AM = am; - + field bits<32> SoftFail = 0; let OutOperandList = outs; let InOperandList = ins; let AsmString = asmstr; @@ -46,6 +46,11 @@ let Inst{31 - 26} = opcode; } +class CSKY16Inst pattern> + : CSKYInst { + field bits<16> Inst; +} + // CSKY 32-bit instruction // Format< OP[6] | Offset[26] > // Instruction(1): bsr32 @@ -157,19 +162,7 @@ let isTerminator = 1; let isReturn = 1; let isBarrier = 1; -} - -// Instructions(1): rte32 -class I_16_RET_I sop, bits<5> pcode, string op, list pattern> - : CSKY32Inst { - let Inst{25 - 21} = sop; - let Inst{20 - 16} = pcode; - let Inst{15 - 10} = 0x10; - let Inst{9 - 5} = 1; - let Inst{4 - 0} = 0; - let isTerminator = 1; - let isReturn = 1; - let isBarrier = 1; + let Uses = [ R15 ]; } // Format< OP[6] | SOP[5] | RX[5] | IMM16[16] > @@ -227,14 +220,27 @@ let Inst{11 - 0} = imm12; } +class I_PLDR opcode, bits<4> sop, dag outs, dag ins, + string op, list pattern> + : CSKY32Inst { + bits<5> rx; + bits<12> imm12; + let Inst{25 - 21} = 0; + let Inst{20 - 16} = rx; + let Inst{15 - 12} = sop; + let Inst{11 - 0} = imm12; +} + + // Format< OP[6] | RZ[5] | RX[5] | SOP[4] | OFFSET[12] > -// Instructions(6): ld32.b, ld32.bs, ld32.h, ld32.hs, ld32.w, ld32.d +// Instructions(6): ld32.b, ld32.bs, ld32.h, ld32.hs, ld32.w class I_LD sop, string op, Operand operand> : I_LDST; // Format< OP[6] | RZ[5] | RX[5] | SOP[4] | OFFSET[12] > -// Instructions(4): st32.b, st32.h, st32.w, st32.d +// Instructions(4): st32.b, st32.h, st32.w class I_ST sop, string op, Operand operand> : I_LDST; @@ -249,6 +255,8 @@ let Inst{20 - 16} = pcode; let Inst{15 - 12} = 0; let Inst{11 - 0} = regs; + let Uses = [R14]; + let Defs = [R14]; } // Format< OP[6] | RZ[5] | RX[5] | SOP[6] | PCODE[5] | IMM[5]> @@ -256,7 +264,7 @@ class I_5_ZX sop, bits<5> pcode, string op, ImmLeaf ImmType, list pattern> : CSKY32Inst { bits<5> rz; bits<5> rx; @@ -272,9 +280,9 @@ // Format< OP[6] | IMM[5] | RX[5] | SOP[6] | PCODE[5] | RZ[5]> // Instructions(13): decgt32, declt32, decne32, lsli32, lslc32, lsri32 // lsrc32, asri32, asrc32, rotli32, xsr32, bclri32, bseti32 -class I_5_XZ sop, bits<5> pcode, string op, dag ins, dag outs, +class I_5_XZ sop, bits<5> pcode, string op, dag outs, dag ins, list pattern> - : CSKY32Inst { bits<5> imm5; bits<5> rx; @@ -286,19 +294,107 @@ let Inst{4 - 0} = rz; } +// mtcr32, mfcr32 +class I_5_XZ_CR sop, bits<5> pcode, string opStr, dag outs, dag ins, + list pattern> + : CSKY32Inst { + bits<5> sel; + bits<5> rx; + bits<5> cr; + let Inst{25 - 21} = sel; + let Inst{20 - 16} = rx; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = pcode; + let Inst{4 - 0} = cr; +} + +// sync +class I_5_XZ_SYNC sop, bits<5> pcode, string opStr, bits<1> S, bits<1> I> + : CSKY32Inst { + let Inst{25 - 21} = 0; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = pcode; + let Inst{4 - 0} = 0; + let Inst{25} = S; + let Inst{21} = I; + +} + +// Priviledged Instructions +class I_5_XZ_PRIVI sop, bits<5> pcode, string opStr> + : CSKY32Inst { + let Inst{25 - 21} = 0; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = pcode; + let Inst{4 - 0} = 0; +} + +class I_CP sop, dag outs, dag ins, string opStr> + : CSKY32Inst { + bits<5> cpid; + bits<12> usdef; + let Inst{25 - 21} = cpid; + let Inst{20 - 16} = 0; + let Inst{15 - 12} = sop; + let Inst{11 - 0} = usdef; +} + +class I_CPOP + : CSKY32Inst { + bits<5> cpid; + bits<20> usdef; + let Inst{25 - 21} = cpid; + let Inst{20 - 16} = usdef{19-15}; + let Inst{15} = 1; + let Inst{14 - 0} = usdef{14-0}; +} + +class I_CP_Z sop, dag outs, dag ins, string opStr> + : CSKY32Inst { + bits<5> cpid; + bits<12> usdef; + bits<5> rz; + + let Inst{25 - 21} = cpid; + let Inst{20 - 16} = rz; + let Inst{15 - 12} = sop; + let Inst{11 - 0} = usdef; +} + +class I_5_CACHE sop, bits<5> pcode, string opStr> + : CSKY32Inst { + let Inst{25 - 21} = pcode; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + +class I_5_X_CACHE sop, bits<5> pcode, string opStr> + : CSKY32Inst { + bits<5> rx; + + let Inst{25 - 21} = pcode; + let Inst{20 - 16} = rx; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + // Format< OP[6] | RY[5] | RX[5] | SOP[6] | PCODE[5] | IMM[5]> // Instructions(2): ldm32, (ldq32), stm32, (stq32) -class I_5_YX opcode, dag outs, dag ins, string op, list pattern, - bits<5> imm5> - : CSKY32Inst(imm5), pattern> { +class I_5_YX opcode, bits<6> sop, dag outs, dag ins, string opStr, list pattern> + : CSKY32Inst { + bits<10> regs; bits<5> rx; - bits<5> ry; - let Inst{25 - 21} = ry; // ry + + let Inst{25 - 21} = regs{9 - 5}; // ry let Inst{20 - 16} = rx; - let Inst{15 - 10} = 0b000111; + let Inst{15 - 10} = sop; let Inst{9 - 5} = 0b00001; - let Inst{4 - 0} = imm5{4 - 0}; // imm5 + let Inst{4 - 0} = regs{4 - 0}; // imm5 } // Format< OP[6] | LSB[5] | RX[5] | SOP[6] | MSB[5] | RZ[5]> @@ -317,14 +413,33 @@ let Inst{4 - 0} = rz; } -// sextb, sexth -class I_5_XZ_US sop, string op, SDNode opnode, - ValueType type> : I_5_XZ_U; +class I_5_XZ_INS sop, dag outs, dag ins, string op, list pattern> + : CSKY32Inst { + bits<5> rx; + bits<5> rz; + bits<5> msb; + bits<5> lsb; + let Inst{25 - 21} = rz; + let Inst{20 - 16} = rx; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = msb; + let Inst{4 - 0} = lsb; +} -class I_5_XZ_UZ sop, string op, int v> - : I_5_XZ_U; +// Format< OP[6] | LSB[5] | RX[5] | SOP[6] | MSB[5] | RZ[5]> +// Instructions(6): zext32, zextb32, zexth32, sext32, sextb32, sexth32 +class I_5_XZ_U2 sop, bits<5> lsb, bits<5> msb, dag outs, dag ins, + string op, list pattern> + : CSKY32Inst { + bits<5> rx; + bits<5> rz; + let Inst{25 - 21} = lsb; // lsb + let Inst{20 - 16} = rx; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = msb; // msb + let Inst{4 - 0} = rz; +} // Format< OP[6] | RZ[5] | RX[5] | SOP[6] | SIZE[5] | LSB[5]> // Instructions(1): ins32 @@ -341,6 +456,16 @@ let Inst{4 - 0} = size_lsb{4 - 0}; // lsb } +// sextb, sexth +class I_5_XZ_US sop, bits<5> lsb, bits<5> msb, string op, + SDNode opnode, ValueType type> + : I_5_XZ_U2; + +class I_5_XZ_UZ sop, bits<5> lsb, bits<5> msb, string op, int v> + : I_5_XZ_U2; + // Format< OP[6] | IMM[5] | RX[5] | SOP[6] | PCODE[5] | 00000 > // Instructions(1): btsti32 class I_5_X sop, bits<5> pcode, string op, ImmLeaf ImmType, @@ -373,6 +498,18 @@ let Inst{4 - 0} = rz; } +class I_5_IMM5 opcode, bits<6> sop, bits<5> pcode, string op, ImmLeaf ImmType, + list pattern> + : CSKY32Inst { + bits<5> imm5; + let Inst{25 - 21} = imm5; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = sop; + let Inst{9 - 5} = pcode; + let Inst{4 - 0} = 0; +} + // Format< OP[6] | RY[5] | RX[5] | SOP[6] | PCODE[5] | RZ[5] > // Instructions(24): addu32, addc32, subu32, subc32, (rsub32), ixh32, ixw32, // ixd32, and32, andn32, or32, xor32, nor32, lsl32, lsr32, asr32, rotl32 @@ -493,9 +630,8 @@ // Format< OP[6] | 00000[5] | RX[5] | SOP[6] | PCODE[5] | 00000[5] > // Instructions:(1) tstnbz32 -class R_X sop, bits<5> pcode, string op, list pattern> - : CSKY32Inst { +class R_X sop, bits<5> pcode, dag outs, dag ins, string op, list pattern> + : CSKY32Inst { bits<5> rx; let Inst{25 - 21} = 0; let Inst{20 - 16} = rx; @@ -530,3 +666,14 @@ let Inst{4 - 0} = 0; let Constraints = "$rz = $false"; } + +class BAR sop, string op, bits<1> signed> + : CSKY32Inst { + let Inst{25} = signed; + let Inst{24 - 16} = 0; + let Inst{15 - 5} = 0x421; + let Inst{4 - 0} = sop; + let hasSideEffects = 1; + let mayLoad = 0; + let mayStore = 0; +} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYInstrInfo.td b/llvm/lib/Target/CSKY/CSKYInstrInfo.td --- a/llvm/lib/Target/CSKY/CSKYInstrInfo.td +++ b/llvm/lib/Target/CSKY/CSKYInstrInfo.td @@ -15,6 +15,18 @@ // CSKY specific DAG Nodes. //===----------------------------------------------------------------------===// +def SDT_CallSeqStart : SDCallSeqStart<[SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; + +def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>, + SDTCisVT<1, i32>]>; + +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_CallSeqStart, + [SDNPHasChain, SDNPOutGlue]>; + +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_CallSeqEnd, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>; + // Target-dependent nodes. def CSKY_RET : SDNode<"CSKYISD::RET", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; @@ -44,6 +56,7 @@ ImmLeaf(Imm - 1);"> { let EncoderMethod = "getOImmOpValue"; let ParserMatchClass = OImmAsmOperand; + let DecoderMethod = "decodeOImmOperand<"#num#">"; } class uimm : Operand, @@ -53,12 +66,14 @@ !if(!ne(shift, 0), UImmAsmOperand, UImmAsmOperand); + let DecoderMethod = "decodeUImmOperand<"#num#", "#shift#">"; } class simm : Operand, ImmLeaf(Imm);"> { let EncoderMethod = "getImmOpValue<"#shift#">"; let ParserMatchClass = SImmAsmOperand; + let DecoderMethod = "decodeSImmOperand<"#num#", "#shift#">"; } def nimm_XFORM : SDNodeXFormgetTargetConstant((N->getZExtValue() >> 16) & 0xFFFF, SDLoc(N), MVT::i32); }]>; +def uimm32_lo16 : SDNodeXFormgetTargetConstant(N->getZExtValue()& 0xFFFF, SDLoc(N), MVT::i32); +}]>; def uimm16_16_xform : Operand, ImmLeaf(Imm);", uimm32_hi16> { let ParserMatchClass = UImmAsmOperand<16>; + let EncoderMethod = "getImmOpValue"; } def uimm_shift : Operand, ImmLeaf(Imm);"> { let EncoderMethod = "getImmShiftOpValue"; let ParserMatchClass = UImmAsmOperand<2>; + let DecoderMethod = "decodeImmShiftOpValue"; } def CSKYSymbol : AsmOperandClass { @@ -94,16 +114,22 @@ let EncoderMethod = "getBranchSymbolOpValue"; let ParserMatchClass = CSKYSymbol; + let DecoderMethod = "decodeSImmOperand<16, 1>"; + let PrintMethod = "printCSKYSymbolOperand"; + let OperandType = "OPERAND_PCREL"; } def call_symbol : Operand { let ParserMatchClass = CSKYSymbol; let EncoderMethod = "getCallSymbolOpValue"; + let DecoderMethod = "decodeSImmOperand<26, 1>"; + let PrintMethod = "printCSKYSymbolOperand"; + let OperandType = "OPERAND_PCREL"; } def Constpool : AsmOperandClass { - let Name = "ConstpoolSymbol"; - let RenderMethod = "addImmOperands"; + let Name = "Constpool"; + let RenderMethod = "addConstpoolOperands"; let DiagnosticType = "InvalidConstpool"; let ParserMethod = "parseConstpoolSymbol"; } @@ -112,24 +138,132 @@ let ParserMatchClass = Constpool; let EncoderMethod = "getConstpoolSymbolOpValue"; + let DecoderMethod = "decodeUImmOperand<16, 2>"; + let PrintMethod = "printConstpool"; + let OperandType = "OPERAND_PCREL"; +} + +def DataAsmClass : AsmOperandClass { + let Name = "DataSymbol"; + let RenderMethod = "addConstpoolOperands"; + let DiagnosticType = "InvalidConstpool"; + let ParserMethod = "parseDataSymbol"; +} + +class data_symbol : Operand { + let ParserMatchClass = Constpool; + let EncoderMethod = + "getDataSymbolOpValue<"#reloc#">"; + let DecoderMethod = "decodeUImmOperand<18, "#shift#">"; + let PrintMethod = "printDataSymbol"; } def bare_symbol : Operand { let ParserMatchClass = CSKYSymbol; let EncoderMethod = "getBareSymbolOpValue"; + let PrintMethod = "printCSKYSymbolOperand"; + let DecoderMethod = "decodeSImmOperand<18, 1>"; + let OperandType = "OPERAND_PCREL"; +} + +def oimm3 : oimm<3>; +def oimm4 : oimm<4>; +def oimm5 : oimm<5>; +def oimm6 : oimm<6>; + +def imm5_idly : Operand, ImmLeaf= 0;"> { + let EncoderMethod = "getImmOpValueIDLY"; + let DecoderMethod = "decodeOImmOperand<5>"; } +def oimm8 : oimm<8>; def oimm12 : oimm<12>; def oimm16 : oimm<16>; def nimm12 : nimm<12>; +def uimm1 : uimm<1>; +def uimm2 : uimm<2>; + + +def uimm2_jmpix : Operand, + ImmLeaf { + let EncoderMethod = "getImmJMPIX"; + let DecoderMethod = "decodeJMPIXImmOperand"; +} + +def uimm3 : uimm<3>; +def uimm4 : uimm<4>; def uimm5 : uimm<5>; +def uimm5_msb_size : uimm<5> { + let EncoderMethod = "getImmOpValueMSBSize"; +} + +def uimm5_1 : uimm<5, 1>; +def uimm5_2 : uimm<5, 2>; +def uimm6 : uimm<6>; +def uimm7 : uimm<7>; +def uimm7_1 : uimm<7, 1>; +def uimm7_2 : uimm<7, 2>; +def uimm7_3 : uimm<7, 3>; +def uimm8 : uimm<8>; +def uimm8_2 : uimm<8, 2>; +def uimm8_3 : uimm<8, 3>; +def uimm8_8 : uimm<8, 8>; +def uimm8_16 : uimm<8, 16>; +def uimm8_24 : uimm<8, 24>; def uimm12 : uimm<12>; def uimm12_1 : uimm<12, 1>; def uimm12_2 : uimm<12, 2>; def uimm16 : uimm<16>; +def uimm16_8 : uimm<16, 8>; +def uimm16_16 : uimm<16, 16>; +def uimm20 : uimm<20>; +def uimm24 : uimm<24>; +def uimm24_8 : uimm<24, 8>; + +def simm8_2 : simm<8, 2>; + +class RegSeqAsmOperand : AsmOperandClass { + let Name = "RegSeq"#Suffix; + let RenderMethod = "addRegSeqOperands"; + let DiagnosticType = "InvalidRegSeq"; + let ParserMethod = "parseRegSeq"; +} + +def regseq : Operand { + let EncoderMethod = "getRegisterSeqOpValue"; + let ParserMatchClass = RegSeqAsmOperand<"">; + let PrintMethod = "printRegisterSeq"; + let DecoderMethod = "DecodeRegSeqOperand"; + let MIOperandInfo = (ops GPR, uimm5); +} +def RegListAsmOperand : AsmOperandClass { + let Name = "RegList"; + let RenderMethod = "addRegListOperands"; + let DiagnosticType = "InvalidRegList"; + let ParserMethod = "parseRegList"; +} + +def reglist : Operand { + let ParserMatchClass = RegListAsmOperand; + let PrintMethod = "printRegisterList"; +} + +def PSRFlag : AsmOperandClass { + let Name = "PSRFlag"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidPSRFlag"; + let ParserMethod = "parsePSRFlag"; +} + +def psrflag : Operand, ImmLeaf(Imm);"> { + let EncoderMethod = "getImmOpValue"; + let ParserMatchClass = PSRFlag; + let PrintMethod = "printPSRFlag"; +} //===----------------------------------------------------------------------===// // Instruction Formats @@ -145,12 +279,33 @@ class BinOpFrag : PatFrag<(ops node:$LHS, node:$RHS), res>; class UnOpFrag : PatFrag<(ops node:$Src), res>; +def eqToAdd : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs), [{ + return isOrEquivalentToAdd(N); +}]>; + +def BaseAddr : ComplexPattern; + + +//===----------------------------------------------------------------------===// +// CSKYPseudo +//===----------------------------------------------------------------------===// + +// Pessimistically assume the stack pointer will be clobbered +let Defs = [R14], Uses = [R14] in { +def ADJCALLSTACKDOWN : CSKYPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "!ADJCALLSTACKDOWN $amt1, $amt2", [(callseq_start timm:$amt1, timm:$amt2)]>; +def ADJCALLSTACKUP : CSKYPseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2), + "!ADJCALLSTACKUP $amt1, $amt2", [(callseq_end timm:$amt1, timm:$amt2)]>; +} // Defs = [R14], Uses = [R14] //===----------------------------------------------------------------------===// // Basic ALU instructions. //===----------------------------------------------------------------------===// +let Predicates = [iHasE2] in { + let isReMaterializable = 1, isAsCheapAsAMove = 1 in { + let isAdd = 1 in def ADDI32 : I_12<0x0, "addi32", add, oimm12>; def SUBI32 : I_12<0x1, "subi32", sub, oimm12>; def ORI32 : I_16_ZX<"ori32", uimm16, @@ -171,11 +326,15 @@ (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), [(set GPR:$rz, (rotl GPR:$rx, uimm5:$imm5))]>; - + def ROTRI32 : CSKYPseudo<(outs GPR:$rz), (ins GPR:$rx, oimm5:$imm5), + "rotri32 $rz, $rx, $imm5", []>; + } + let isAdd = 1 in def ADDU32 : R_YXZ_SP_F1<0x0, 0x1, BinOpFrag<(add node:$LHS, node:$RHS)>, "addu32", 1>; def SUBU32 : R_YXZ_SP_F1<0x0, 0x4, BinOpFrag<(sub node:$LHS, node:$RHS)>, "subu32">; + def MULT32 : R_YXZ_SP_F1<0x21, 0x1, BinOpFrag<(mul node:$LHS, node:$RHS)>, "mult32", 1>; def AND32 : R_YXZ_SP_F1<0x8, 0x1, @@ -188,8 +347,16 @@ BinOpFrag<(xor node:$LHS, node:$RHS)>, "xor32", 1>; def NOR32 : R_YXZ_SP_F1<0x9, 0x4, BinOpFrag<(not (or node:$LHS, node:$RHS))>, "nor32", 1>; + let isCodeGenOnly = 1 in def NOT32 : R_XXZ<0b001001, 0b00100, (outs GPR:$rz), (ins GPR:$rx), "not32", [(set GPR:$rz, (not GPR:$rx))]>; + + let Size = 8 in + def NEG32 : CSKYPseudo<(outs GPR:$rd), (ins GPR:$rx), "neg32 $rd, $rx", []>; + + let Size = 8 in + def RSUBI32 : CSKYPseudo<(outs GPR:$rd), (ins GPR:$rx, uimm12:$imm12), "rsubi32 $rd, $rx, $imm12", []>; + def LSL32 : R_YXZ_SP_F1<0x10, 0x1, BinOpFrag<(shl node:$LHS, node:$RHS)>, "lsl32">; def LSR32 : R_YXZ_SP_F1<0x10, 0x2, @@ -199,23 +366,37 @@ def ROTL32 : R_YXZ_SP_F1<0x10, 0x8, BinOpFrag<(rotl node:$LHS, (and node:$RHS, 0x1f))>, "rotl32">; - // TODO: Shift series instr. with carry. + def BMASKI32 : I_5_Z<0b010100, 0x1, "bmaski32", oimm5, []>; + def LSLC32 : I_5_XZ<0x13, 0x1, "lslc32", + (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, oimm5:$imm5), []>; + def LSRC32 : I_5_XZ<0x13, 0x2, "lsrc32", + (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, oimm5:$imm5), []>; + def ASRC32 : I_5_XZ<0x13, 0x4, "asrc32", + (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, oimm5:$imm5), []>; + def XSR32 : I_5_XZ<0x13, 0x8, "xsr32", + (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, oimm5:$imm5, CARRY:$cin), []>; def IXH32 : R_YXZ_SP_F1<0x2, 0x1, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 1)))>, "ixh32">; def IXW32 : R_YXZ_SP_F1<0x2, 0x2, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 2)))>, "ixw32">; - + let Predicates = [iHas2E3] in def IXD32 : R_YXZ_SP_F1<0x2, 0x4, BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 3)))>, "ixd32">; - let isCommutable = 1 in + let isCommutable = 1, isAdd = 1 in def ADDC32 : R_YXZ<0x31, 0x0, 0x2, (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, GPR:$ry, CARRY:$cin), "addc32", []>; def SUBC32 : R_YXZ<0x31, 0x0, 0x8, (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, GPR:$ry, CARRY:$cin), "subc32", []>; - // TODO: incf32. + def INCF32 : I_5_ZX<0x3, 0x1, "incf32", uimm5, []>; + def INCT32 : I_5_ZX<0x3, 0x2, "inct32", uimm5, []>; + def DECF32 : I_5_ZX<0x3, 0x4, "decf32", uimm5, []>; + def DECT32 : I_5_ZX<0x3, 0x8, "dect32", uimm5, []>; +} + +let Predicates = [iHas2E3] in { def DIVS32 : R_YXZ_SP_F1<0x20, 0x2, BinOpFrag<(sdiv node:$LHS, node:$RHS)>, "divs32">; def DIVU32 : R_YXZ_SP_F1<0x20, 0x1, @@ -228,11 +409,35 @@ def DECNE32 : I_5_XZ<0x4, 0x4, "decne32", (outs GPR:$rz, CARRY:$cout), (ins GPR:$rx, uimm5:$imm5), []>; - // TODO: s/zext. - def ZEXT32 : I_5_XZ_U<0x15, (outs GPR:$rz), - (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "zext32",[]>; - def SEXT32 : I_5_XZ_U<0x16, (outs GPR:$rz), - (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "sext32", []>; + def SEXT32 : I_5_XZ_U<0x16, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "sext32", []>; + let isCodeGenOnly = 1 in { + def SEXTB32 : I_5_XZ_US<0x16, 0, 7, "sextb32", sext_inreg, i8>; + def SEXTH32 : I_5_XZ_US<0x16, 0, 15, "sexth32", sext_inreg, i16>; + def ZEXTB32 : I_5_XZ_UZ<0x15, 0, 7, "zextb32", 255>; + def ZEXTH32 : I_5_XZ_UZ<0x15, 0, 15, "zexth32", 65535>; + } + def ZEXT32 : I_5_XZ_U<0x15, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "zext32",[]>; + + let Constraints = "$rZ = $rz" in + def INS32 : I_5_XZ_INS<0b010111, (outs GPR:$rz), (ins GPR:$rZ, GPR:$rx, uimm5_msb_size:$msb, uimm5:$lsb), "ins32", []>; +} + +let Predicates = [iHas3E3r1] in { +def MULTS32 : R_YXZ<0x3e, 0x20, 0x10, (outs GPRPair:$rz), + (ins GPR:$rx, GPR:$ry), "mul.s32", []>; +def MULTU32 : R_YXZ<0x3e, 0x20, 0x00, (outs GPRPair:$rz), + (ins GPR:$rx, GPR:$ry), "mul.u32", []>; + +let Constraints = "$rZ = $rz" in { +def MULATS32 : R_YXZ<0x3e, 0x20, 0x14, (outs GPRPair:$rZ), + (ins GPRPair:$rz, GPR:$rx, GPR:$ry), "mula.s32", []>; +def MULATU32 : R_YXZ<0x3e, 0x20, 0x04, (outs GPRPair:$rZ), + (ins GPRPair:$rz, GPR:$rx, GPR:$ry), "mula.u32", []>; +} +} + +def MULSH32 : R_YXZ<0x31, 0b100100, 0b00001, (outs GPR:$rz), + (ins GPR:$rx, GPR:$ry), "mulsh32", []>; //===----------------------------------------------------------------------===// // Load & Store instructions. @@ -242,18 +447,35 @@ def LD32H : I_LD; def LD32W : I_LD; +let OutOperandList = (outs GPRPair:$rz) in +def LD32D : I_LD; +let Predicates = [iHasE2] in { def LD32BS : I_LD; def LD32HS : I_LD; - // TODO: LDM and STM. + def LDM32 : I_5_YX<0b110100, 0b000111, + (outs), (ins GPR:$rx, regseq:$regs, variable_ops), "ldm32\t$regs, (${rx})", []>; + def STM32 : I_5_YX<0b110101, 0b000111, + (outs), (ins GPR:$rx, regseq:$regs, variable_ops), "stm32\t$regs, (${rx})", []>; + + let Size = 4, isCodeGenOnly = 0 in { + def LDQ32 : CSKYPseudo<(outs), (ins GPR:$rx, regseq:$regs, variable_ops), + "ldq32\t$regs, (${rx})", []>; + def STQ32 : CSKYPseudo<(outs), (ins GPR:$rx, regseq:$regs, variable_ops), + "stq32\t$regs, (${rx})", []>; + } +} def ST32B : I_ST; def ST32H : I_ST; def ST32W : I_ST; +let InOperandList = (ins GPRPair:$rz, GPR:$rx, uimm12_2:$imm12 ) in +def ST32D : I_ST; +let Predicates = [iHas2E3] in { def LDR32B : I_LDR<0x0, "ldr32.b">; def LDR32BS : I_LDR<0x4, "ldr32.bs">; def LDR32H : I_LDR<0x1, "ldr32.h">; @@ -262,42 +484,100 @@ def STR32B : I_STR<0x0, "str32.b">; def STR32H : I_STR<0x1, "str32.h">; def STR32W : I_STR<0x2, "str32.w">; +} + +// Indicate that we're dumping the CR register, so we'll need to +// scavenge a register for it. +let mayStore = 1 in { +def SPILL_CARRY : CSKYPseudo<(outs), (ins CARRY:$cond, GPR:$rx, uimm12_2:$imm), + "!SPILL_CARRY $cond, $rx, $imm", []>; +} + +// Indicate that we're restoring the CR register (previously +// spilled), so we'll need to scavenge a register for it. +let mayLoad = 1 in { +def RESTORE_CARRY : CSKYPseudo<(outs CARRY:$cond), (ins GPR:$rx, uimm12_2:$imm), + "!RESTORE_CARRY $cond, $rx, $imm", []>; +} + +let mayLoad = 1 in { +def STORE_PAIR : CSKYPseudo<(outs), (ins GPRPair:$rz, GPR:$rx, uimm12_2:$imm), + "!STORE_PAIR $rz, $rx, $imm", []>; +} - //TODO: SPILL_CARRY and RESTORE_CARRY. +let mayLoad = 1 in { +def LOAD_PAIR : CSKYPseudo<(outs GPRPair:$rz), (ins GPR:$rx, uimm12_2:$imm), + "!LOAD_PAIR $rz, $rx, $imm", []>; +} //===----------------------------------------------------------------------===// // Compare instructions. //===----------------------------------------------------------------------===// - +let Predicates = [iHasE2] in { def CMPNEI32 : I_16_X<0x1A, "cmpnei32", uimm16>; def CMPHSI32 : I_16_X<0x18, "cmphsi32", oimm16>; def CMPLTI32 : I_16_X<0x19, "cmplti32", oimm16>; - - + def CMPLEI32 : CSKYPseudo<(outs CARRY:$ca), (ins GPR:$rx, uimm16:$imm16), + "cmplei32\t$rx, $imm16", []>; +} +let Predicates = [iHas2E3] in { def CMPNE32 : R_YX<0x1, 0x4, "cmpne32">; def CMPHS32 : R_YX<0x1, 0x1, "cmphs32">; def CMPLT32 : R_YX<0x1, 0x2, "cmplt32">; - // TODO: setc and clrc. - // TODO: test32 and tstnbz. + def SETC32 : CSKY32Inst { + let Inst{25 - 21} = 0; //rx + let Inst{20 - 16} = 0; //ry + let Inst{15 - 10} = 0x1; + let Inst{9 - 5} = 0x1; + let Inst{4 - 0} = 0; + let isCompare = 1; + } + def CLRC32 : CSKY32Inst { + let Inst{25 - 21} = 0; //rx + let Inst{20 - 16} = 0; //ry + let Inst{15 - 10} = 0x1; + let Inst{9 - 5} = 0x4; + let Inst{4 - 0} = 0; + let isCompare = 1; + } + + def TST32 : R_YX<0x8, 0x4, "tst32">; + def TSTNBZ32 : R_X<0x8, 0x8, + (outs CARRY:$ca), (ins GPR:$rx), "tstnbz32", []>; +} //===----------------------------------------------------------------------===// // Data move instructions. //===----------------------------------------------------------------------===// +let Predicates= [iHasE2] in { + let isCodeGenOnly = 1 in { def MOVT32 : R_ZX<0x3, 0x2, "movt32", []>; def MOVF32 : R_ZX<0x3, 0x1, "movf32", []>; + } def MOVI32 : I_16_MOV<0x10, "movi32", uimm16>; + let Size = 4, isCodeGenOnly = 0 in + def BGENI : CSKYPseudo<(outs GPR:$dst), (ins uimm5:$imm), "bgeni\t$dst, $imm", []>; + def : InstAlias<"bgeni16 $dst, $imm", (BGENI GPR:$dst, uimm5:$imm)>; + def : InstAlias<"bgeni32 $dst, $imm", (BGENI GPR:$dst, uimm5:$imm)>; def MOVIH32 : I_16_MOV<0x11, "movih32", uimm16_16_xform>; def MVC32 : R_Z_1<0x1, 0x8, "mvc32">; + let isCodeGenOnly = 1 in def MOV32 : R_XZ<0x12, 0x1, "mov32">; - // TODO: ISEL Pseudo. + let usesCustomInserter = 1 in + def ISEL32 : CSKYPseudo<(outs GPR:$dst), (ins CARRY:$cond, GPR:$src1, GPR:$src2), + "!isel32\t$dst, $src1, src2", [(set GPR:$dst, (select CARRY:$cond, GPR:$src1, GPR:$src2))]>; +} +let Predicates = [iHas2E3] in { def MVCV32 : R_Z_1<0x1, 0x10, "mvcv32">; - // TODO: clrf and clrt. def CLRF32 : R_Z_2<0xB, 0x1, "clrf32", []>; def CLRT32 : R_Z_2<0xB, 0x2, "clrt32", []>; +} //===----------------------------------------------------------------------===// // Branch and call instructions. @@ -309,12 +589,12 @@ [(br bb:$imm16)]>; def BT32 : I_16_L<0x3, (outs), (ins CARRY:$ca, br_symbol:$imm16), - "bt32\t$imm16", [(brcond CARRY:$ca, bb:$imm16)]>; + "bt32\t$imm16", [(brcond CARRY:$ca, bb:$imm16)]>, Requires<[iHasE2]>; def BF32 : I_16_L<0x2, (outs), (ins CARRY:$ca, br_symbol:$imm16), - "bf32\t$imm16", []>; + "bf32\t$imm16", []>, Requires<[iHasE2]>; } - +let Predicates = [iHas2E3] in { def BEZ32 : I_16_X_L<0x8, "bez32", br_symbol>; def BNEZ32 : I_16_X_L<0x9, "bnez32", br_symbol>; def BHZ32 : I_16_X_L<0xA, "bhz32", br_symbol>; @@ -334,10 +614,25 @@ let isCall = 1, Defs = [ R15 ] , mayLoad = 1 in def JSRI32: I_16_L<0x17, (outs), (ins constpool_symbol:$imm16), "jsri32\t$imm16", []>; +} +def BNEZAD32 : CSKY32Inst { + bits<5> rx; + bits<16> imm16; + let Inst{25 - 21} = 0x1; + let Inst{20 - 16} = rx; + let Inst{15 - 0} = imm16; + let isBranch = 1; + let isTerminator = 1; + let Constraints = "$rx_u = $rx"; + let Predicates = [iHas2E3, iHas10E60]; +} def BSR32 : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>; +def : InstAlias<"bsr $dst", (BSR32 call_symbol:$dst)>; + def BSR32_BR : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>{ let isCodeGenOnly = 1; let isBranch = 1; @@ -347,27 +642,308 @@ let Defs = [ R15 ]; } - +let Predicates = [iHasE2], isCodeGenOnly = 1 in { def RTS32 : I_16_RET<0x6, 0xF, "rts32", [(CSKY_RET)]>; +} -def RTE32 : I_16_RET_I<0, 0, "rte32", []>; - //===----------------------------------------------------------------------===// // Symbol address instructions. //===----------------------------------------------------------------------===// +def data_symbol_b : data_symbol<"CSKY::fixup_csky_doffset_imm18", 0>; +def data_symbol_h : data_symbol<"CSKY::fixup_csky_doffset_imm18_scale2", 1>; +def data_symbol_w : data_symbol<"CSKY::fixup_csky_doffset_imm18_scale4", 2> { + let ParserMatchClass = DataAsmClass; +} + +let Predicates = [iHas2E3] in { + def GRS32 : I_18_Z_L<0x3, "grs32\t$rz, $offset", (outs GPR:$rz), (ins bare_symbol:$offset), []>; +def : InstAlias<"grs\t$rz, $offset", (GRS32 GPR:$rz, bare_symbol:$offset)>; + +let Uses = [R28] in { +def LRS32B : I_18_Z_L<0x0, "lrs32.b\t$rz, $offset", + (outs GPR:$rz), (ins data_symbol_b:$offset), []>; +def LRS32H : I_18_Z_L<0x1, "lrs32.h\t$rz, $offset", + (outs GPR:$rz), (ins data_symbol_h:$offset), []>; +def LRS32W : I_18_Z_L<0x2, "lrs32.w\t$rz, $offset", + (outs GPR:$rz), (ins data_symbol_w:$offset), []>; +def SRS32B : I_18_Z_L<0x4, "srs32.b\t$rz, $offset", + (outs), (ins GPR:$rz, data_symbol_b:$offset), []>; +def SRS32H : I_18_Z_L<0x5, "srs32.h\t$rz, $offset", + (outs), (ins GPR:$rz, data_symbol_h:$offset), []>; +def SRS32W : I_18_Z_L<0x6, "srs32.w\t$rz, $offset", + (outs), (ins GPR:$rz, data_symbol_w:$offset), []>; +} + +def PUSH32 : I_12_PP<0b11111, 0b00000, (outs), (ins reglist:$regs, variable_ops), "push32 $regs">; + +let Uses = [R14, R15], isReturn = 1, isTerminator = 1, isBarrier = 1 in +def POP32 : I_12_PP<0b11110, 0b00000, (outs), (ins reglist:$regs, variable_ops), "pop32 $regs">; + +} let mayLoad = 1, mayStore = 0 in { def LRW32 : I_16_Z_L<0x14, "lrw32", (ins constpool_symbol:$imm16), []>; let isCodeGenOnly = 1 in -def LRW32_Gen : I_16_Z_L<0x14, "lrw32", - (ins bare_symbol:$src1, constpool_symbol:$imm16), []>; +def LRW32_Gen : I_16_Z_L<0x14, "lrw32", (ins bare_symbol:$src1, constpool_symbol:$imm16), []>; +} + +//===----------------------------------------------------------------------===// +// Atomic and fence instructions. +//===----------------------------------------------------------------------===// + +let Predicates = [iHasMP1E2] in { + def BRWARW : BAR<0b01111, "bar.brwarw", 0>; + def BRWARWS : BAR<0b01111, "bar.brwarws", 1>; + def BRARW : BAR<0b00111, "bar.brarw", 0>; + def BRARWS : BAR<0b00111, "bar.brarws", 1>; + def BRWAW : BAR<0b01110, "bar.brwaw", 0>; + def BRWAWS : BAR<0b01110, "bar.brwaws", 1>; + def BRAR : BAR<0b00101, "bar.brar", 0>; + def BRARS : BAR<0b00101, "bar.brars", 1>; + def BWAW : BAR<0b01010, "bar.bwaw", 0>; + def BWAWS : BAR<0b01010, "bar.bwaws", 1>; + + def LDEX32W : I_LD; + let Constraints = "$rd = $rz" in + def STEX32W : I_LDST; +} + +//===----------------------------------------------------------------------===// +// Other operation instructions. +//===----------------------------------------------------------------------===// + +let Predicates = [iHas2E3] in { + def BREV32 : R_XZ<0x18, 0x10, "brev32">; + def ABS32 : R_XZ<0x0, 0x10, "abs32">; + def BGENR32 : R_XZ<0x14, 0x2, "bgenr32">; +} + +let Predicates = [iHasE2] in { + def REVB32 : R_XZ<0x18, 0x4, "revb32">; + def REVH32 : R_XZ<0x18, 0x8, "revh32">; + def FF0 : R_XZ<0x1F, 0x1, "ff0.32">; + def FF1 : R_XZ<0x1F, 0x2, "ff1.32">; + def XTRB0 : R_XZ<0x1C, 0x1, "xtrb0.32">; + def XTRB1 : R_XZ<0x1C, 0x2, "xtrb1.32">; + def XTRB2 : R_XZ<0x1C, 0x4, "xtrb2.32">; + def XTRB3 : R_XZ<0x1C, 0x8, "xtrb3.32">; + def BTSTI32 : I_5_X<0x0A, 0x4, "btsti32", uimm5, []>; + def BCLRI32 : I_5_XZ<0xA, 0x1, "bclri32", + (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), []>; + def BSETI32 : I_5_XZ<0xA, 0x2, "bseti32", + (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5), []>; +} + +//===----------------------------------------------------------------------===// +// Special instructions. +//===----------------------------------------------------------------------===// + +def MFFCR : CSKY32Inst { + bits<5> rx; + + let Inst{25 - 21} = 0b00010; + let Inst{20 - 16} = 0b00001; + let Inst{15 - 10} = 0b011000; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = rx; + let hasSideEffects = 1; + let isCodeGenOnly = 1; +} + +def MTFCR : CSKY32Inst { + bits<5> rx; + + let Inst{25 - 21} = 0b00010; + let Inst{20 - 16} = rx; + let Inst{15 - 10} = 0b011001; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0b00001; + let hasSideEffects = 1; + let isCodeGenOnly = 1; +} + +def SYNC32 : I_5_IMM5<0x30, 0b000001, 0b00001, "sync32", uimm5, []>; + +def SYNC0_32 : CSKY32Inst { + let Inst{25 - 21} = 0; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = 0b000001; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + +def SYNC_32_I : CSKY32Inst { + let Inst{25 - 21} = 1; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = 0b000001; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + +def SYNC_32_S : CSKY32Inst { + let Inst{25 - 21} = 0b10000; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = 0b000001; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + +def SYNC_32_IS : CSKY32Inst { + let Inst{25 - 21} = 0b10001; + let Inst{20 - 16} = 0; + let Inst{15 - 10} = 0b000001; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; +} + +let Predicates = [iHas2E3] in { + def RFI32 : I_5_XZ_PRIVI<0x11, 0x1, "rfi32">; + def SCE32 : I_5_IMM5<0x30, 0b000110, 0b00001, "sce32", uimm4, []>; +} +let Predicates = [HasExtendLrw] in +def IDLY32 : I_5_IMM5<0x30, 0b000111, 0b00001, "idly32", imm5_idly, []>; +def STOP32 : I_5_XZ_PRIVI<0x12, 0x1, "stop32">; +def WAIT32 : I_5_XZ_PRIVI<0x13, 0x1, "wait32">; +def DOZE32 : I_5_XZ_PRIVI<0x14, 0x1, "doze32">; +def WE32 : I_5_XZ_PRIVI<0b010101, 0x1, "we32">; +def SE32 : I_5_XZ_PRIVI<0b010110, 0x1, "se32">; +def WSC32 : I_5_XZ_PRIVI<0b001111, 0x1, "wsc32">; + +def CPOP32 : I_CPOP<(outs), (ins uimm5:$cpid, uimm20:$usdef), "cpop32 <$cpid, ${usdef}>">; +def CPRC32 : I_CP<0b0100, (outs CARRY:$ca), (ins uimm5:$cpid, uimm12:$usdef), "cprc32 <$cpid, ${usdef}>">; +def CPRCR32 : I_CP_Z<0b0010, (outs GPR:$rz), (ins uimm5:$cpid, uimm12:$usdef), "cprcr32 $rz, <$cpid, ${usdef}>">; +def CPRGR32 : I_CP_Z<0b0000, (outs GPR:$rz), (ins uimm5:$cpid, uimm12:$usdef), "cprgr32 $rz, <$cpid, ${usdef}>">; +def CPWCR32 : I_CP_Z<0b0011, (outs), (ins GPR:$rz, uimm5:$cpid, uimm12:$usdef), "cpwcr32 $rz, <$cpid, ${usdef}>">; +def CPWGR32 : I_CP_Z<0b0001, (outs), (ins GPR:$rz, uimm5:$cpid, uimm12:$usdef), "cpwgr32 $rz, <$cpid, ${usdef}>">; + +let Predicates = [iHas3r2E3r3] in { +def DCACHE_IALL32 : I_5_CACHE<0b100101, 0b01000, "dcache32.iall">; +def DCACHE_CALL32 : I_5_CACHE<0b100101, 0b00100, "dcache32.call">; +def DCACHE_CIALL32 : I_5_CACHE<0b100101, 0b01100, "dcache32.ciall">; +def DCACHE_IVA32 : I_5_X_CACHE<0b100101, 0b01011, "dcache32.iva">; +def DCACHE_ISW32: I_5_X_CACHE<0b100101, 0b01010, "dcache32.isw">; +def DCACHE_CVA32 : I_5_X_CACHE<0b100101, 0b00111, "dcache32.cva">; +def DCACHE_CVAL32 : I_5_X_CACHE<0b100101, 0b10111, "dcache32.cval1">; +def DCACHE_CSW32 : I_5_X_CACHE<0b100101, 0b00110, "dcache32.csw">; +def DCACHE_CIVA32 : I_5_X_CACHE<0b100101, 0b01111, "dcache32.civa">; +def DCACHE_CISW32 : I_5_X_CACHE<0b100101, 0b01110, "dcache32.cisw">; + +def ICACHE_IALL32 : I_5_CACHE<0b100100, 0b01000, "icache32.iall">; +def ICACHE_IALLS32 : I_5_CACHE<0b100100, 0b11000, "icache32.ialls">; +def ICACHE_IVA32 : I_5_X_CACHE<0b100100, 0b01011, "icache32.iva">; + +def TLBI_VAA32 : I_5_X_CACHE<0b100010, 0b00010, "tlbi32.vaa">; +def TLBI_VAAS32 : I_5_X_CACHE<0b100010, 0b10010, "tlbi32.vaas">; +def TLBI_ASID32 : I_5_X_CACHE<0b100010, 0b00001, "tlbi32.asid">; +def TLBI_ASIDS32 : I_5_X_CACHE<0b100010, 0b10001, "tlbi32.asids">; +def TLBI_VA32 : I_5_X_CACHE<0b100010, 0b00011, "tlbi32.va">; +def TLBI_VAS32 : I_5_X_CACHE<0b100010, 0b10011, "tlbi32.vas">; +def TLBI_ALL32 : I_5_CACHE<0b100010, 0b00000, "tlbi32.all">; +def TLBI_ALLS32 : I_5_CACHE<0b100010, 0b10000, "tlbi32.alls">; + +def L2CACHE_IALL : I_5_CACHE<0b100110, 0b01000, "l2cache.iall">; +def L2CACHE_CALL : I_5_CACHE<0b100110, 0b00100, "l2cache.call">; +def L2CACHE_CIALL : I_5_CACHE<0b100110, 0b01100, "l2cache.ciall">; +} + +def PLDR32 :I_PLDR; +def PLDW32 :I_PLDR; + +def TRAP32 : CSKY32Inst { + bits<2> imm2; + + let Inst{25 - 21} = 0; + let Inst{20 - 16} = 0; + let Inst{15 - 12} = 0b0010; + let Inst{11 - 10} = imm2; + let Inst{9 - 5} = 0b00001; + let Inst{4 - 0} = 0; + +} + + +//===----------------------------------------------------------------------===// +// Pseudo for assembly +//===----------------------------------------------------------------------===// + +let isCall = 1, Defs = [ R15 ], mayLoad = 1, Size = 4, isCodeGenOnly = 0 in +def JBSR32 : CSKYPseudo<(outs), (ins call_symbol:$src1), "jbsr32\t$src1", []>; + +def : InstAlias<"jbsr\t$src1", (JBSR32 call_symbol:$src1)>; + +def JBR32 : CSKYPseudo<(outs), (ins br_symbol:$src1), "jbr32\t$src1", []> { + let isBranch = 1; + let isTerminator = 1; + let isBarrier = 1; + let isIndirectBranch = 1; + let mayLoad = 1; + let Size = 4; +} + +def JBT32 : CSKYPseudo<(outs), (ins CARRY:$ca, br_symbol:$src1), "jbt32\t$src1", []> { + let isBranch = 1; + let isTerminator = 1; + let isIndirectBranch = 1; + let mayLoad = 1; + let Size = 4; +} + +def JBF32 : CSKYPseudo<(outs), (ins CARRY:$ca, br_symbol:$src1), "jbf32\t$src1", []> { + let isBranch = 1; + let isTerminator = 1; + let isIndirectBranch = 1; + let mayLoad = 1; + let Size = 4; +} + +def JBT_E : CSKYPseudo<(outs), (ins CARRY:$ca, br_symbol:$src1), "!jbt_e\t$src1", []> { + let isBranch = 1; + let isTerminator = 1; + let isIndirectBranch = 1; + let mayLoad = 1; + let Size = 6; } -// TODO: Atomic and fence instructions. -// TODO: Other operations. -// TODO: Special instructions. -// TODO: Pseudo for assembly. +def JBF_E : CSKYPseudo<(outs), (ins CARRY:$ca, br_symbol:$src1), "!jbf_e\t$src1", []> { + let isBranch = 1; + let isTerminator = 1; + let isIndirectBranch = 1; + let mayLoad = 1; + let Size = 6; +} + +let mayLoad = 1, Size = 2, isCodeGenOnly = 0 in +def PseudoLRW32 : CSKYPseudo<(outs GPR:$rz), (ins bare_symbol:$src), "lrw32 $rz, $src", []>; + + +def : InstAlias<"lrw $rz, $src", (PseudoLRW32 GPR:$rz, bare_symbol:$src)>; +def : InstAlias<"lrw $rz, $src", (LRW32 GPR:$rz, constpool_symbol:$src)>; + +let mayLoad = 1, Size = 4, isCodeGenOnly = 0 in +def PseudoJSRI32 : CSKYPseudo<(outs), (ins call_symbol:$src), "jsri32 $src", []>; +def : InstAlias<"jsri $dst", (PseudoJSRI32 call_symbol:$dst)>; +def : InstAlias<"jsri $dst", (JSRI32 constpool_symbol:$dst)>; + +let mayLoad = 1, Size = 4, isCodeGenOnly = 0 in +def PseudoJMPI32 : CSKYPseudo<(outs), (ins br_symbol:$src), "jmpi32 $src", []>; +def : InstAlias<"jmpi $dst", (PseudoJMPI32 br_symbol:$dst)>; +def : InstAlias<"jmpi $dst", (JMPI32 constpool_symbol:$dst)>; + +let isNotDuplicable = 1, mayLoad = 1, mayStore = 0, Size = 8 in +def PseudoTLSLA32 : CSKYPseudo<(outs GPR:$dst1, GPR:$dst2), + (ins constpool_symbol:$src, i32imm:$label), "!tlslrw32\t$dst1, $dst2, $src, $label", []>; + +let hasSideEffects = 0, isNotDuplicable = 1 in +def CONSTPOOL_ENTRY : CSKYPseudo<(outs), + (ins i32imm:$instid, i32imm:$cpidx, i32imm:$size), "", []>; \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYSubtarget.h b/llvm/lib/Target/CSKY/CSKYSubtarget.h new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYSubtarget.h @@ -0,0 +1,87 @@ +//===-- CSKYSubtarget.h - Define Subtarget for the CSKY----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the CSKY specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_CSKY_CSKYSUBTARGET_H +#define LLVM_LIB_TARGET_CSKY_CSKYSUBTARGET_H + +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/Target/TargetMachine.h" + +#define GET_SUBTARGETINFO_HEADER +#include "CSKYGenSubtargetInfo.inc" + +namespace llvm { +class StringRef; + +class CSKYSubtarget : public CSKYGenSubtargetInfo { + virtual void anchor(); + + CSKYFrameLowering FrameLowering; + CSKYInstrInfo InstrInfo; + CSKYRegisterInfo RegInfo; + CSKYTargetLowering TLInfo; + SelectionDAGTargetInfo TSInfo; + + bool HasE1; + bool HasE2; + bool Has2E3; + bool HasMP; + bool Has3E3r1; + bool Has3r1E3r2; + bool Has3r2E3r3; + bool Has3E7; + bool HasMP1E2; + bool Has7E10; + bool Has10E60; + +public: + CSKYSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, + StringRef FS, const TargetMachine &TM); + + const CSKYFrameLowering *getFrameLowering() const override { + return &FrameLowering; + } + const CSKYInstrInfo *getInstrInfo() const override { return &InstrInfo; } + const CSKYRegisterInfo *getRegisterInfo() const override { return &RegInfo; } + const CSKYTargetLowering *getTargetLowering() const override { + return &TLInfo; + } + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { + return &TSInfo; + } + + /// Initializes using the passed in CPU and feature strings so that we can + /// use initializer lists for subtarget initialization. + CSKYSubtarget &initializeSubtargetDependencies(const Triple &TT, + StringRef CPU, + StringRef TuneCPU, + StringRef FS); + + // Generated by inc file + void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS); + + bool hasE1() const { return HasE1; } + bool hasE2() const { return HasE2; } + bool has2E3() const { return Has2E3; } + bool has3r1E3r2() const { return Has3r1E3r2; } + bool has3r2E3r3() const { return Has3r2E3r3; } + bool has3E3r1() const { return Has3E3r1; } + bool has3E7() const { return Has3E7; } + bool hasMP() const { return HasMP; } + bool hasMP1E2() const { return HasMP1E2; } + bool has7E10() const { return Has7E10; } + bool has10E60() const { return Has10E60; } +}; +} // namespace llvm + +#endif // LLVM_LIB_TARGET_CSKY_CSKYSUBTARGET_H \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/CSKYSubtarget.cpp b/llvm/lib/Target/CSKY/CSKYSubtarget.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/Target/CSKY/CSKYSubtarget.cpp @@ -0,0 +1,52 @@ +//===-- CSKYSubtarget.h - Define Subtarget for the CSKY----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the CSKY specific subclass of TargetSubtargetInfo. +// +//===----------------------------------------------------------------------===// + +#include "CSKYSubtarget.h" + +using namespace llvm; + +#define DEBUG_TYPE "csky-subtarget" +#define GET_SUBTARGETINFO_TARGET_DESC +#define GET_SUBTARGETINFO_CTOR +#include "CSKYGenSubtargetInfo.inc" + +void CSKYSubtarget::anchor() {} + +CSKYSubtarget &CSKYSubtarget::initializeSubtargetDependencies( + const Triple &TT, StringRef CPUName, StringRef TuneCPUName, StringRef FS) { + + if (CPUName.empty()) + CPUName = "generic"; + if (TuneCPUName.empty()) + TuneCPUName = CPUName; + + HasE1 = false; + HasE2 = false; + Has2E3 = false; + HasMP = false; + Has3E3r1 = false; + Has3r1E3r2 = false; + Has3r2E3r3 = false; + Has3E7 = false; + HasMP1E2 = false; + Has7E10 = false; + Has10E60 = false; + + ParseSubtargetFeatures(CPUName, TuneCPUName, FS); + return *this; +} + +CSKYSubtarget::CSKYSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU, + StringRef FS, const TargetMachine &TM) + : CSKYGenSubtargetInfo(TT, CPU, TuneCPU, FS), + FrameLowering(initializeSubtargetDependencies(TT, CPU, TuneCPU, FS)), + InstrInfo(*this), RegInfo(), TLInfo(TM, *this) {} \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp @@ -30,25 +30,57 @@ static llvm::DenseMap Infos = { {CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_addr_hi16, {"fixup_csky_addr_hi16", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_addr_lo16, {"fixup_csky_addr_lo16", 0, 32, 0}}, {CSKY::Fixups::fixup_csky_pcrel_imm16_scale2, {"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, {CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4, - {"fixup_csky_pcrel_uimm16_scale4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {"fixup_csky_pcrel_uimm16_scale4", 0, 32, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, + {CSKY::Fixups::fixup_csky_pcrel_uimm8_scale4, + {"fixup_csky_pcrel_uimm8_scale4", 0, 32, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, {CSKY::Fixups::fixup_csky_pcrel_imm26_scale2, {"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, {CSKY::Fixups::fixup_csky_pcrel_imm18_scale2, - {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}}; + {"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_got32, {"fixup_csky_got32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_got_imm18_scale4, + {"fixup_csky_got_imm18_scale4", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_gotoff, {"fixup_csky_gotoff", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_gotpc, + {"fixup_csky_gotpc", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_plt32, {"fixup_csky_plt32", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_plt_imm18_scale4, + {"fixup_csky_plt_imm18_scale4", 0, 32, 0}}, + {CSKY::Fixups::fixup_csky_pcrel_imm10_scale2, + {"fixup_csky_pcrel_imm10_scale2", 0, 16, MCFixupKindInfo::FKF_IsPCRel}}, + {CSKY::Fixups::fixup_csky_pcrel_uimm7_scale4, + {"fixup_csky_pcrel_uimm7_scale4", 0, 16, + MCFixupKindInfo::FKF_IsPCRel | + MCFixupKindInfo::FKF_IsAlignedDownTo32Bits}}, + {CSKY::Fixups::fixup_csky_doffset_imm18, + {"fixup_csky_doffset_imm18", 0, 18, 0}}, + {CSKY::Fixups::fixup_csky_doffset_imm18_scale2, + {"fixup_csky_doffset_imm18_scale2", 0, 18, 0}}, + {CSKY::Fixups::fixup_csky_doffset_imm18_scale4, + {"fixup_csky_doffset_imm18_scale4", 0, 18, 0}}}; + assert(Infos.size() == CSKY::NumTargetFixupKinds && "Not all fixup kinds added to Infos array"); - assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && - "Invalid kind!"); - if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) + if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind) { + assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() && + "Invalid kind!"); + return Infos[Kind]; - else if (Kind < FirstTargetFixupKind) + } else if (Kind < FirstTargetFixupKind) { return MCAsmBackend::getFixupKindInfo(Kind); - else + } else { return MCAsmBackend::getFixupKindInfo(FK_NONE); + } } static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value, diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYFixupKinds.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYFixupKinds.h --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYFixupKinds.h +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYFixupKinds.h @@ -16,6 +16,10 @@ enum Fixups { fixup_csky_addr32 = FirstTargetFixupKind, + fixup_csky_addr_hi16, + + fixup_csky_addr_lo16, + fixup_csky_pcrel_imm16_scale2, fixup_csky_pcrel_uimm16_scale4, @@ -24,6 +28,29 @@ fixup_csky_pcrel_imm18_scale2, + fixup_csky_gotpc, + + fixup_csky_gotoff, + + fixup_csky_got32, + + fixup_csky_got_imm18_scale4, + + fixup_csky_plt32, + + fixup_csky_plt_imm18_scale4, + + fixup_csky_pcrel_imm10_scale2, + + fixup_csky_pcrel_uimm7_scale4, + + fixup_csky_pcrel_uimm8_scale4, + + fixup_csky_doffset_imm18, + + fixup_csky_doffset_imm18_scale2, + + fixup_csky_doffset_imm18_scale4, // Marker fixup_csky_invalid, NumTargetFixupKinds = fixup_csky_invalid - FirstTargetFixupKind @@ -31,4 +58,4 @@ } // end namespace CSKY } // end namespace llvm -#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYFIXUPKINDS_H +#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYFIXUPKINDS_H \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h @@ -19,6 +19,9 @@ namespace llvm { class CSKYInstPrinter : public MCInstPrinter { +private: + bool ABIRegNames = false; + public: CSKYInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, const MCRegisterInfo &MRI) @@ -43,10 +46,24 @@ unsigned OpIdx, unsigned PrintMethodIdx, const MCSubtargetInfo &STI, raw_ostream &O); + void printDataSymbol(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printConstpool(const MCInst *MI, uint64_t Address, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printPSRFlag(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); + void printRegisterSeq(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printRegisterList(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printCSKYSymbolOperand(const MCInst *MI, uint64_t Address, unsigned OpNo, + const MCSubtargetInfo &STI, raw_ostream &O); + void printSPAddr(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O); static const char *getRegisterName(unsigned RegNo); static const char *getRegisterName(unsigned RegNo, unsigned AltIdx); }; } // namespace llvm -#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H +#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CSKYInstPrinter.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" @@ -95,6 +96,107 @@ MO.getExpr()->print(O, &MAI); } +void CSKYInstPrinter::printDataSymbol(const MCInst *MI, unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + + O << "["; + if (MO.isImm()) + O << MO.getImm(); + else + MO.getExpr()->print(O, &MAI); + O << "]"; +} + +void CSKYInstPrinter::printConstpool(const MCInst *MI, uint64_t Address, + unsigned OpNo, const MCSubtargetInfo &STI, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + + if (MO.isImm()) { + if (PrintBranchImmAsAddress) { + uint64_t Target = Address + MO.getImm(); + Target &= 0xfffffffc; + O << formatHex(Target); + } else { + O << MO.getImm(); + } + return; + } + + assert(MO.isExpr() && "Unknown operand kind in printConstpool"); + + O << "["; + MO.getExpr()->print(O, &MAI); + O << "]"; +} + +void CSKYInstPrinter::printCSKYSymbolOperand(const MCInst *MI, uint64_t Address, + unsigned OpNo, + const MCSubtargetInfo &STI, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + if (!MO.isImm()) { + return printOperand(MI, OpNo, STI, O); + } + + if (PrintBranchImmAsAddress) { + uint64_t Target = Address + MO.getImm(); + Target &= 0xffffffff; + O << formatHex(Target); + } else { + O << MO.getImm(); + } +} + +void CSKYInstPrinter::printRegisterSeq(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + printRegName(O, MI->getOperand(OpNum).getReg()); + O << "-"; + printRegName(O, MI->getOperand(OpNum + 1).getReg()); +} + +void CSKYInstPrinter::printRegisterList(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + auto V = MI->getOperand(OpNum).getImm(); + ListSeparator LS; + + if (V & 0xf) { + O << LS; + printRegName(O, CSKY::R4); + auto Offset = (V & 0xf) - 1; + if (Offset) { + O << "-"; + printRegName(O, CSKY::R4 + Offset); + } + } + + if ((V >> 4) & 0x1) { + O << LS; + printRegName(O, CSKY::R15); + } + + if ((V >> 5) & 0x7) { + O << LS; + printRegName(O, CSKY::R16); + + auto Offset = ((V >> 5) & 0x7) - 1; + + if (Offset) { + O << "-"; + printRegName(O, CSKY::R16 + Offset); + } + } + + if ((V >> 8) & 0x1) { + O << LS; + printRegName(O, CSKY::R28); + } +} + const char *CSKYInstPrinter::getRegisterName(unsigned RegNo) { return getRegisterName(RegNo, ArchRegNames ? CSKY::NoRegAltName : CSKY::ABIRegAltName); diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.h --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.h +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.h @@ -13,8 +13,8 @@ #ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H #define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H -#include "CSKYMCExpr.h" #include "MCTargetDesc/CSKYFixupKinds.h" +#include "MCTargetDesc/CSKYMCExpr.h" #include "llvm/MC/MCCodeEmitter.h" #include "llvm/MC/MCContext.h" @@ -49,14 +49,40 @@ SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCOperand &MO = MI.getOperand(Idx); - assert(MO.isImm() && "Unexpected MO type."); - return (MO.getImm() >> shift); + if (MO.isImm()) + return (MO.getImm() >> shift); + + assert(MO.isExpr() && "Unexpected MO type."); + + MCFixupKind Kind = getTargetFixup(MO.getExpr()); + Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc())); + return 0; } + unsigned getRegSeqImmOpValue(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getRegisterSeqOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getOImmOpValue(const MCInst &MI, unsigned Idx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const; + unsigned getImmOpValueIDLY(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getImmJMPIX(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getImmOpValueMSBSize(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + unsigned getImmShiftOpValue(const MCInst &MI, unsigned Idx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -101,6 +127,21 @@ return 0; } + template + unsigned getDataSymbolOpValue(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(Idx); + assert(MO.isExpr() && "Unexpected MO type."); + + MCFixupKind Kind = MCFixupKind(FIXUP); + if (MO.getExpr()->getKind() == MCExpr::Target) + Kind = getTargetFixup(MO.getExpr()); + + Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc())); + return 0; + } + unsigned getCallSymbolOpValue(const MCInst &MI, unsigned Idx, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { @@ -132,4 +173,4 @@ } // namespace llvm -#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H +#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.cpp --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.cpp +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "CSKYMCCodeEmitter.h" +#include "CSKYMCExpr.h" #include "MCTargetDesc/CSKYMCTargetDesc.h" #include "llvm/ADT/Statistic.h" #include "llvm/MC/MCInstBuilder.h" @@ -31,11 +32,46 @@ return MO.getImm() - 1; } +unsigned +CSKYMCCodeEmitter::getImmOpValueIDLY(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(Idx); + assert(MO.isImm() && "Unexpected MO type."); + + auto V = (MO.getImm() <= 3) ? 4 : MO.getImm(); + return V - 1; +} + +unsigned +CSKYMCCodeEmitter::getImmOpValueMSBSize(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MSB = MI.getOperand(Idx); + const MCOperand &LSB = MI.getOperand(Idx + 1); + assert(MSB.isImm() && LSB.isImm() && "Unexpected MO type."); + + return MSB.getImm() - LSB.getImm(); +} + +static void writeData(uint32_t Bin, unsigned Size, raw_ostream &OS) { + uint16_t LO16 = static_cast(Bin); + uint16_t HI16 = static_cast(Bin >> 16); + + if (Size == 4) + support::endian::write(OS, HI16, support::little); + + support::endian::write(OS, LO16, support::little); +} + void CSKYMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, SmallVectorImpl &Fixups, const MCSubtargetInfo &STI) const { const MCInstrDesc &Desc = MII.get(MI.getOpcode()); unsigned Size = Desc.getSize(); + + ++MCNumEmitted; + uint32_t Bin = getBinaryCodeForInstr(MI, Fixups, STI); uint16_t LO16 = static_cast(Bin); @@ -45,7 +81,6 @@ support::endian::write(OS, HI16, support::little); support::endian::write(OS, LO16, support::little); - ++MCNumEmitted; // Keep track of the # of mi's emitted. } unsigned @@ -62,6 +97,51 @@ return 0; } +unsigned +CSKYMCCodeEmitter::getRegSeqImmOpValue(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + assert(MI.getOperand(Idx).isReg() && "Unexpected MO type."); + assert(MI.getOperand(Idx + 1).isImm() && "Unexpected MO type."); + + unsigned Ry = MI.getOperand(Idx).getReg(); + unsigned Rz = MI.getOperand(Idx + 1).getImm(); + + unsigned Imm = Ctx.getRegisterInfo()->getEncodingValue(Rz) - + Ctx.getRegisterInfo()->getEncodingValue(Ry); + + return ((Ctx.getRegisterInfo()->getEncodingValue(Ry) << 5) | Imm); +} + +unsigned +CSKYMCCodeEmitter::getRegisterSeqOpValue(const MCInst &MI, unsigned Op, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned Reg1 = + Ctx.getRegisterInfo()->getEncodingValue(MI.getOperand(Op).getReg()); + unsigned Reg2 = + Ctx.getRegisterInfo()->getEncodingValue(MI.getOperand(Op + 1).getReg()); + + unsigned Binary = ((Reg1 & 0x1f) << 5) | (Reg2 - Reg1); + + return Binary; +} + +unsigned CSKYMCCodeEmitter::getImmJMPIX(const MCInst &MI, unsigned Idx, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + if (MI.getOperand(Idx).getImm() == 16) + return 0; + else if (MI.getOperand(Idx).getImm() == 24) + return 1; + else if (MI.getOperand(Idx).getImm() == 32) + return 2; + else if (MI.getOperand(Idx).getImm() == 40) + return 3; + else + assert(0); +} + MCFixupKind CSKYMCCodeEmitter::getTargetFixup(const MCExpr *Expr) const { const CSKYMCExpr *CSKYExpr = cast(Expr); @@ -70,6 +150,22 @@ llvm_unreachable("Unhandled fixup kind!"); case CSKYMCExpr::VK_CSKY_ADDR: return MCFixupKind(CSKY::fixup_csky_addr32); + case CSKYMCExpr::VK_CSKY_ADDR_HI16: + return MCFixupKind(CSKY::fixup_csky_addr_hi16); + case CSKYMCExpr::VK_CSKY_ADDR_LO16: + return MCFixupKind(CSKY::fixup_csky_addr_lo16); + case CSKYMCExpr::VK_CSKY_GOT: + return MCFixupKind(CSKY::fixup_csky_got32); + case CSKYMCExpr::VK_CSKY_GOTPC: + return MCFixupKind(CSKY::fixup_csky_gotpc); + case CSKYMCExpr::VK_CSKY_GOTOFF: + return MCFixupKind(CSKY::fixup_csky_gotoff); + case CSKYMCExpr::VK_CSKY_PLT: + return MCFixupKind(CSKY::fixup_csky_plt32); + case CSKYMCExpr::VK_CSKY_PLT_IMM18_BY4: + return MCFixupKind(CSKY::fixup_csky_plt_imm18_scale4); + case CSKYMCExpr::VK_CSKY_GOT_IMM18_BY4: + return MCFixupKind(CSKY::fixup_csky_got_imm18_scale4); } } @@ -79,4 +175,4 @@ return new CSKYMCCodeEmitter(Ctx, MCII); } -#include "CSKYGenMCCodeEmitter.inc" +#include "CSKYGenMCCodeEmitter.inc" \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.h --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.h +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.h @@ -19,13 +19,20 @@ enum VariantKind { VK_CSKY_None, VK_CSKY_ADDR, + VK_CSKY_ADDR_HI16, + VK_CSKY_ADDR_LO16, VK_CSKY_PCREL, VK_CSKY_GOT, + VK_CSKY_GOT_IMM18_BY4, VK_CSKY_GOTPC, VK_CSKY_GOTOFF, VK_CSKY_PLT, - VK_CSKY_TPOFF, + VK_CSKY_PLT_IMM18_BY4, + VK_CSKY_TLSIE, + VK_CSKY_TLSLE, VK_CSKY_TLSGD, + VK_CSKY_TLSLDO, + VK_CSKY_TLSLDM, VK_CSKY_Invalid }; @@ -66,4 +73,4 @@ }; } // end namespace llvm -#endif +#endif \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.cpp b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.cpp --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.cpp +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.cpp @@ -26,22 +26,33 @@ switch (Kind) { default: llvm_unreachable("Invalid ELF symbol kind"); + case VK_CSKY_None: case VK_CSKY_ADDR: return ""; - case VK_CSKY_PCREL: - return ""; + case VK_CSKY_ADDR_HI16: + return "@HI16"; + case VK_CSKY_ADDR_LO16: + return "@LO16"; + case VK_CSKY_GOT_IMM18_BY4: case VK_CSKY_GOT: return "@GOT"; case VK_CSKY_GOTPC: return "@GOTPC"; case VK_CSKY_GOTOFF: return "@GOTOFF"; + case VK_CSKY_PLT_IMM18_BY4: case VK_CSKY_PLT: return "@PLT"; - case VK_CSKY_TPOFF: + case VK_CSKY_TLSLE: return "@TPOFF"; + case VK_CSKY_TLSIE: + return "@GOTTPOFF"; case VK_CSKY_TLSGD: - return "@TLSGD"; + return "@TLSGD32"; + case VK_CSKY_TLSLDO: + return "@TLSLDO32"; + case VK_CSKY_TLSLDM: + return "@TLSLDM32"; } } @@ -87,7 +98,8 @@ switch (getKind()) { default: return; - case VK_CSKY_TPOFF: + case VK_CSKY_TLSLE: + case VK_CSKY_TLSIE: case VK_CSKY_TLSGD: break; } @@ -106,17 +118,20 @@ switch (getKind()) { default: return true; - - case VK_CSKY_ADDR: - case VK_CSKY_PCREL: case VK_CSKY_GOT: + case VK_CSKY_GOT_IMM18_BY4: case VK_CSKY_GOTPC: case VK_CSKY_GOTOFF: - case VK_CSKY_TPOFF: + case VK_CSKY_PLT: + case VK_CSKY_PLT_IMM18_BY4: + case VK_CSKY_TLSIE: + case VK_CSKY_TLSLE: case VK_CSKY_TLSGD: + case VK_CSKY_TLSLDO: + case VK_CSKY_TLSLDM: return false; } } return true; } \ No newline at end of file diff --git a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h --- a/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h +++ b/llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.h @@ -45,4 +45,7 @@ #define GET_INSTRINFO_ENUM #include "CSKYGenInstrInfo.inc" -#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCTARGETDESC_H +#define GET_SUBTARGETINFO_ENUM +#include "CSKYGenSubtargetInfo.inc" + +#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCTARGETDESC_H \ No newline at end of file diff --git a/llvm/test/MC/CSKY/basic.s b/llvm/test/MC/CSKY/basic.s --- a/llvm/test/MC/CSKY/basic.s +++ b/llvm/test/MC/CSKY/basic.s @@ -1,4 +1,5 @@ -# RUN: llvm-mc %s -triple=csky -show-encoding | FileCheck -check-prefixes=CHECK-ASM %s +# RUN: llvm-mc %s -triple=csky -show-encoding -csky-no-aliases -mattr=+e2 -mattr=+2e3 \ +# RUN: -mattr=+mp1e2 | FileCheck -check-prefixes=CHECK-ASM %s # CHECK-ASM: addi32 a0, sp, 2 # CHECK-ASM: encoding: [0x0e,0xe4,0x01,0x00] @@ -40,6 +41,46 @@ # CHECK-ASM: encoding: [0x4e,0xc4,0x00,0x49] rotli32 a0, sp, 2 +# CHECK-ASM: incf32 a0, sp, 2 +# CHECK-ASM: encoding: [0x0e,0xc4,0x22,0x0c] +incf32 a0, sp, 2 + +# CHECK-ASM: inct32 a0, sp, 2 +# CHECK-ASM: encoding: [0x0e,0xc4,0x42,0x0c] +inct32 a0, sp, 2 + +# CHECK-ASM: decf32 a0, sp, 2 +# CHECK-ASM: encoding: [0x0e,0xc4,0x82,0x0c] +decf32 a0, sp, 2 + +# CHECK-ASM: dect32 a0, sp, 2 +# CHECK-ASM: encoding: [0x0e,0xc4,0x02,0x0d] +dect32 a0, sp, 2 + +# CHECK-ASM: decgt32 a0, sp, 2 +# CHECK-ASM: encoding: [0x4e,0xc4,0x20,0x10] +decgt32 a0, sp, 2 + +# CHECK-ASM: declt32 a0, sp, 2 +# CHECK-ASM: encoding: [0x4e,0xc4,0x40,0x10] +declt32 a0, sp, 2 + +# CHECK-ASM: decne32 a0, sp, 2 +# CHECK-ASM: encoding: [0x4e,0xc4,0x80,0x10] +decne32 a0, sp, 2 + +# CHECK-ASM: btsti32 a0, 2 +# CHECK-ASM: encoding: [0x40,0xc4,0x80,0x28] +btsti32 a0, 2 + +# CHECK-ASM: bclri32 a0, sp, 2 +# CHECK-ASM: encoding: [0x4e,0xc4,0x20,0x28] +bclri32 a0, sp, 2 + +# CHECK-ASM: bseti32 a0, sp, 2 +# CHECK-ASM: encoding: [0x4e,0xc4,0x40,0x28] +bseti32 a0, sp, 2 + # CHECK-ASM: cmpnei32 a0, 2 # CHECK-ASM: encoding: [0x40,0xeb,0x02,0x00] cmpnei32 a0, 2 @@ -92,6 +133,10 @@ # CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x40] lsl32 a3, l0, l1 +# CHECK-ASM: rotl32 a3, l0, l1 +# CHECK-ASM: encoding: [0xa4,0xc4,0x03,0x41] +rotl32 a3, l0, l1 + # CHECK-ASM: lsr32 a3, l0, l1 # CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x40] lsr32 a3, l0, l1 @@ -100,6 +145,26 @@ # CHECK-ASM: encoding: [0xa4,0xc4,0x83,0x40] asr32 a3, l0, l1 +# CHECK-ASM: lslc32 a0, sp, 2 +# CHECK-ASM: encoding: [0x2e,0xc4,0x20,0x4c] +lslc32 a0, sp, 2 + +# CHECK-ASM: lsrc32 a0, sp, 2 +# CHECK-ASM: encoding: [0x2e,0xc4,0x40,0x4c] +lsrc32 a0, sp, 2 + +# CHECK-ASM: asrc32 a0, sp, 2 +# CHECK-ASM: encoding: [0x2e,0xc4,0x80,0x4c] +asrc32 a0, sp, 2 + +# CHECK-ASM: xsr32 a0, sp, 2 +# CHECK-ASM: encoding: [0x2e,0xc4,0x00,0x4d] +xsr32 a0, sp, 2 + +# CHECK-ASM: bmaski32 a3, 17 +# CHECK-ASM: encoding: [0x00,0xc6,0x23,0x50] +bmaski32 a3, 17 + # CHECK-ASM: mult32 a3, l0, l1 # CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x84] mult32 a3, l0, l1 @@ -156,6 +221,10 @@ # CHECK-ASM: encoding: [0xae,0xd0,0x80,0x00] ldr32.b a0, (sp, l1 << 2) +# CHECK-ASM: ldex32.w a0, (sp, 4) +# CHECK-ASM: encoding: [0x0e,0xd8,0x01,0x70] +ldex32.w a0, (sp, 4) + # CHECK-ASM: ldr32.bs a0, (sp, l1 << 2) # CHECK-ASM: encoding: [0xae,0xd0,0x80,0x10] ldr32.bs a0, (sp, l1 << 2) @@ -184,6 +253,10 @@ # CHECK-ASM: encoding: [0x0e,0xdc,0x01,0x20] st32.w a0, (sp, 4) +# CHECK-ASM: stex32.w a0, (sp, 4) +# CHECK-ASM: encoding: [0x0e,0xdc,0x01,0x70] +stex32.w a0, (sp, 4) + # CHECK-ASM: str32.b a0, (sp, l1 << 2) # CHECK-ASM: encoding: [0xae,0xd4,0x80,0x00] str32.b a0, (sp, l1 << 2) @@ -196,21 +269,65 @@ # CHECK-ASM: encoding: [0xae,0xd4,0x00,0x09] str32.w a0, (sp, l1 << 3) -# CHECK-ASM: not32 a3, l0 -# CHECK-ASM: encoding: [0x84,0xc4,0x83,0x24] -not32 a3, l0 +# CHECK-ASM: ldm32 a1-a2, (a0) +# CHECK-ASM: encoding: [0x20,0xd0,0x21,0x1c] +ldm32 a1-a2, (a0) + +# CHECK-ASM: stm32 a1-a2, (a0) +# CHECK-ASM: encoding: [0x20,0xd4,0x21,0x1c] +stm32 a1-a2, (a0) + +# CHECK-ASM: ldm32 l0-l3, (a0) +# CHECK-ASM: encoding: [0x80,0xd0,0x23,0x1c] +ldq32 r4-r7, (a0) + +# CHECK-ASM: stm32 l0-l3, (a0) +# CHECK-ASM: encoding: [0x80,0xd4,0x23,0x1c] +stq32 r4-r7, (a0) + +# CHECK-ASM: brev32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x03,0x62] +brev32 a3, l0 + +# CHECK-ASM: abs32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x03,0x02] +abs32 a3, l0 + +# CHECK-ASM: bgenr32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x43,0x50] +bgenr32 a3, l0 + +# CHECK-ASM: revb32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x83,0x60] +revb32 a3, l0 + +# CHECK-ASM: revh32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x03,0x61] +revh32 a3, l0 + +# CHECK-ASM: ff0.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x23,0x7c] +ff0.32 a3, l0 + +# CHECK-ASM: ff1.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x43,0x7c] +ff1.32 a3, l0 + +# CHECK-ASM: xtrb0.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x23,0x70] +xtrb0.32 a3, l0 -# CHECK-ASM: mov32 a3, l0 -# CHECK-ASM: encoding: [0x04,0xc4,0x23,0x48] -mov32 a3, l0 +# CHECK-ASM: xtrb1.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x43,0x70] +xtrb1.32 a3, l0 -# CHECK-ASM: movt32 a3, l0 -# CHECK-ASM: encoding: [0x64,0xc4,0x40,0x0c] -movt32 a3, l0 +# CHECK-ASM: xtrb2.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x83,0x70] +xtrb2.32 a3, l0 -# CHECK-ASM: movf32 a3, l0 -# CHECK-ASM: encoding: [0x64,0xc4,0x20,0x0c] -movf32 a3, l0 +# CHECK-ASM: xtrb3.32 a3, l0 +# CHECK-ASM: encoding: [0x04,0xc4,0x03,0x71] +xtrb3.32 a3, l0 # CHECK-ASM: mvc32 a3 # CHECK-ASM: encoding: [0x00,0xc4,0x03,0x05] @@ -240,6 +357,110 @@ # CHECK-ASM: encoding: [0x04,0xc4,0xe3,0x58] sext32 a3, l0, 7, 0 +# CHECK-ASM: ldm32 l1-l3, (a0) +# CHECK-ASM: encoding: [0xa0,0xd0,0x22,0x1c] +ldm32 r5-r7, (a0) + +# CHECK-ASM: stm32 l1-l3, (a0) +# CHECK-ASM: encoding: [0xa0,0xd4,0x22,0x1c] +stm32 r5-r7, (a0) + +# CHECK-ASM: setc32 +# CHECK-ASM: encoding: [0x00,0xc4,0x20,0x04] +setc32 + +# CHECK-ASM: clrc32 +# CHECK-ASM: encoding: [0x00,0xc4,0x80,0x04] +clrc32 + +# CHECK-ASM: tst32 a3, l0 +# CHECK-ASM: encoding: [0x83,0xc4,0x80,0x20] +tst32 a3, l0 + +# CHECK-ASM: tstnbz32 a3 +# CHECK-ASM: encoding: [0x03,0xc4,0x00,0x21] +tstnbz32 a3 + +# CHECK-ASM: clrf32 a3 +# CHECK-ASM: encoding: [0x60,0xc4,0x20,0x2c] +clrf32 a3 + +# CHECK-ASM: clrt32 a3 +# CHECK-ASM: encoding: [0x60,0xc4,0x40,0x2c] +clrt32 a3 + +# CHECK-ASM: bar.brwarw +# CHECK-ASM: encoding: [0x00,0xc0,0x2f,0x84] +bar.brwarw + +# CHECK-ASM: bar.brwarws +# CHECK-ASM: encoding: [0x00,0xc2,0x2f,0x84] +bar.brwarws + +# CHECK-ASM: bar.brarw +# CHECK-ASM: encoding: [0x00,0xc0,0x27,0x84] +bar.brarw + +# CHECK-ASM: bar.brarws +# CHECK-ASM: encoding: [0x00,0xc2,0x27,0x84] +bar.brarws + +# CHECK-ASM: bar.brwaw +# CHECK-ASM: encoding: [0x00,0xc0,0x2e,0x84] +bar.brwaw + +# CHECK-ASM: bar.brwaws +# CHECK-ASM: encoding: [0x00,0xc2,0x2e,0x84] +bar.brwaws + +# CHECK-ASM: bar.brar +# CHECK-ASM: encoding: [0x00,0xc0,0x25,0x84] +bar.brar + +# CHECK-ASM: bar.brars +# CHECK-ASM: encoding: [0x00,0xc2,0x25,0x84] +bar.brars + +# CHECK-ASM: bar.bwaw +# CHECK-ASM: encoding: [0x00,0xc0,0x2a,0x84] +bar.bwaw + +# CHECK-ASM: bar.bwaws +# CHECK-ASM: encoding: [0x00,0xc2,0x2a,0x84] +bar.bwaws + +# CHECK-ASM: sync32 +# CHECK-ASM: encoding: [0x00,0xc0,0x20,0x04] +sync32 + +# CHECK-ASM: sync32.s +# CHECK-ASM: encoding: [0x00,0xc2,0x20,0x04] +sync32.s + +# CHECK-ASM: sync32.i +# CHECK-ASM: encoding: [0x20,0xc0,0x20,0x04] +sync32.i + +# CHECK-ASM: sync32.is +# CHECK-ASM: encoding: [0x20,0xc2,0x20,0x04] +sync32.is + +# CHECK-ASM: rfi32 +# CHECK-ASM: encoding: [0x00,0xc0,0x20,0x44] +rfi32 + +# CHECK-ASM: stop32 +# CHECK-ASM: encoding: [0x00,0xc0,0x20,0x48] +stop32 + +# CHECK-ASM: wait32 +# CHECK-ASM: encoding: [0x00,0xc0,0x20,0x4c] +wait32 + +# CHECK-ASM: doze32 +# CHECK-ASM: encoding: [0x00,0xc0,0x20,0x50] +doze32 + # CHECK-ASM: br32 .L.test # CHECK-ASM: encoding: [A,0xe8'A',A,A] # CHECK-ASM: fixup A - offset: 0, value: .L.test, kind: fixup_csky_pcrel_imm16_scale2 @@ -298,7 +519,7 @@ # CHECK-ASM: encoding: [0xc3,0xe8,0x00,0x00] jmp32 a3 -# CHECK-ASM: jmpi32 .L.test10 +# CHECK-ASM: jmpi32 [.L.test10] # CHECK-ASM: encoding: [0xc0'A',0xea'A',A,A] # CHECK-ASM: fixup A - offset: 0, value: .L.test10, kind: fixup_csky_pcrel_uimm16_scale4 .L.test10: @@ -314,29 +535,25 @@ # CHECK-ASM: encoding: [0xe3,0xe8,0x00,0x00] jsr32 a3 -# CHECK-ASM: jsri32 .L.test12 +# CHECK-ASM: jsri32 [.L.test12] # CHECK-ASM: encoding: [0xe0'A',0xea'A',A,A] # CHECK-ASM: fixup A - offset: 0, value: .L.test12, kind: fixup_csky_pcrel_uimm16_scale4 .L.test12: jsri32 [.L.test12] -# CHECK-ASM: rts32 -# CHECK-ASM: encoding: [0xcf,0xe8,0x00,0x00] -rts32 - # CHECK-ASM: grs32 a0, .L.test13 # CHECK-ASM: encoding: [0x0c'A',0xcc'A',A,A] # CHECK-ASM: fixup A - offset: 0, value: .L.test13, kind: fixup_csky_pcrel_imm18_scale2 .L.test13: grs32 a0, .L.test13 -# CHECK-ASM: lrw32 a0, .L.test14 +# CHECK-ASM: lrw32 a0, [.L.test14] # CHECK-ASM: encoding: [0x80'A',0xea'A',A,A] # CHECK-ASM: fixup A - offset: 0, value: .L.test14, kind: fixup_csky_pcrel_uimm16_scale4 .L.test14: lrw32 a0, [.L.test14] -# RUN: not llvm-mc -triple csky --defsym=ERR=1 < %s 2>&1 | FileCheck %s +# RUN: not llvm-mc -triple csky -mattr=+e2 -mattr=+2e3 --defsym=ERR=1 < %s 2>&1 | FileCheck %s .ifdef ERR @@ -404,9 +621,10 @@ xori32 a0, a1 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction xor32 a0, a2 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction -# Need label -br32 0x100 # CHECK: :[[@LINE]]:6: error: operand must be a symbol name -jmpi32 0x100 # CHECK: :[[@LINE]]:8: error: operand must be a constpool symbol name -bsr32 0x100 # CHECK: :[[@LINE]]:7: error: operand must be a symbol name +ldm32 a1-a33, (a1) # CHECK: :[[#@LINE]]:10: error: invalid register +stm32 a1-a33, (a1) # CHECK: :[[#@LINE]]:10: error: invalid register + +ldq32 a1-a2, (a1) # CHECK: :[[#@LINE]]:1: error: Register sequence is not valid. 'r4-r7' expected +stq32 a1-a3, (a1) # CHECK: :[[#@LINE]]:1: error: Register sequence is not valid. 'r4-r7' expected -.endif +.endif \ No newline at end of file