Index: lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp =================================================================== --- lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp +++ lib/Target/NDS32/AsmParser/NDS32AsmParser.cpp @@ -99,6 +99,8 @@ bool parseOperand(OperandVector &, StringRef Mnemonic); + int matchCPURegisterName(StringRef Symbol); + int matchMRegisterName(StringRef Symbol); int tryParseRegister(); public: @@ -232,18 +234,31 @@ } void addExpr(MCInst &Inst, const MCExpr *Expr) const { + // Add as immediate when possible. Null MCExpr = 0. + if (!Expr) + Inst.addOperand(MCOperand::createImm(0)); + else if (const MCConstantExpr *CE = dyn_cast(Expr)) + Inst.addOperand(MCOperand::createImm(CE->getValue())); + else + Inst.addOperand(MCOperand::createExpr(Expr)); } void addRegOperands(MCInst &Inst, unsigned N) const { + Inst.addOperand(MCOperand::createReg(getReg())); } /// Render the operand to an MCInst as a GPR /// Asserts if the wrong number of operands are requested, or the operand /// is not a k_RegisterIndex compatible with RegKind_GPR void addGPRAsmRegOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(getGPRReg())); } void addImmOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const MCExpr *Expr = getImm(); + addExpr(Inst, Expr); } void addMemRegOffsetOperands(MCInst &Inst, unsigned N) const { @@ -295,28 +310,28 @@ bool isMem() const override { return Kind == k_Memory; } bool isRegList() const { return Kind == k_RegList; } bool isImm5s() const { - return false; + return isConstantImm() && isIntN(5, getConstantImm()); } bool isImm11s() const { - return false; + return isConstantImm() && isIntN(11, getConstantImm()); } bool isImm15s() const { - return false; + return isConstantImm() && isIntN(15, getConstantImm()); } bool isImm20s() const { - return false; + return isConstantImm() && isIntN(20, getConstantImm()); } bool isImm3u() const { - return false; + return isConstantImm() && isUIntN(3, getConstantImm()); } bool isImm5u() const { - return false; + return isConstantImm() && isUIntN(5, getConstantImm()); } bool isImm15u() const { - return false; + return isConstantImm() ? isUIntN(15, getConstantImm()) : isImm(); } bool isImm20u() const { - return false; + return isConstantImm() ? isUIntN(20, getConstantImm()) : isImm(); } bool isMemNoOffset() const { return false; @@ -428,11 +443,17 @@ static std::unique_ptr createGPRReg(unsigned Index, const MCRegisterInfo *RegInfo, SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + return CreateReg(Index, RegKind_GPR, RegInfo, S, E, Parser); } static std::unique_ptr CreateImm(const MCExpr *Val, SMLoc S, SMLoc E, NDS32AsmParser &Parser) { + auto Op = make_unique(k_Immediate, Parser); + Op->Imm.Val = Val; + Op->StartLoc = S; + Op->EndLoc = E; + return Op; } static std::unique_ptr @@ -504,30 +525,167 @@ bool NDS32AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) { - return false; + const AsmToken &Tok = getParser().getTok(); + StartLoc = Tok.getLoc(); + EndLoc = Tok.getEndLoc(); + RegNo = tryParseRegister(); + + return (RegNo == (unsigned)-1); } OperandMatchResultTy NDS32AsmParser::parseImm(OperandVector &Operands) { + DEBUG(dbgs() << "parseImm\n"); + MCAsmParser &Parser = getParser(); + switch (getLexer().getKind()) { + default: + DEBUG(dbgs() << "match immediate fail\n"); + return MatchOperand_NoMatch; + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::String: + break; + } + + const MCExpr *IdVal; + SMLoc S = Parser.getTok().getLoc(); + if (getParser().parseExpression(IdVal)) + return MatchOperand_ParseFail; + + SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1); + Operands.push_back(NDS32Operand::CreateImm(IdVal, S, E, *this)); + DEBUG(dbgs() << "match immediate success\n"); + return MatchOperand_Success; } OperandMatchResultTy NDS32AsmParser::parseAnyRegister(OperandVector &Operands) { - return MatchOperand_Success; + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseAnyRegister\n"); + + Parser.Lex(); // $ + const AsmToken &Tok = getParser().getTok(); + SMLoc S = Tok.getLoc(); + if (Tok.isNot(AsmToken::Identifier)) + return MatchOperand_NoMatch; + + std::string lowerCase = Tok.getString().lower(); + Parser.Lex(); // Eat identifier token. + + int RegNum = matchCPURegisterName(lowerCase); + if (RegNum != -1) { + Operands.push_back(NDS32Operand::createGPRReg( + RegNum, getContext().getRegisterInfo(), S, getLexer().getLoc(), *this)); + DEBUG(dbgs() << "match GPR register success\n"); + return MatchOperand_Success; + } + return MatchOperand_NoMatch; +} + +int NDS32AsmParser::matchCPURegisterName(StringRef Name) { + int CC; + + CC = StringSwitch(Name) + .Case("r0", 0) + .Case("r1", 1) + .Case("r2", 2) + .Case("r3", 3) + .Case("r4", 4) + .Case("r5", 5) + .Case("r6", 6) + .Case("r7", 7) + .Case("r8", 8) + .Case("r9", 9) + .Case("r10",10) + .Case("r11",11) + .Case("r12",12) + .Case("r13",13) + .Case("r14",14) + .Case("r15",15) + .Case("r16",16) + .Case("r17",17) + .Case("r18",18) + .Case("r19",19) + .Case("r20",20) + .Case("r21",21) + .Case("r22",22) + .Case("r23",23) + .Case("r24",24) + .Case("r25",25) + .Case("r26",26) + .Case("r27",27) + .Case("fp", 28) + .Case("gp", 29) + .Case("lp", 30) + .Case("sp", 31) + .Default(-1); + + return CC; } +/// @name Auto-generated Match Functions +/// { + +static unsigned MatchRegisterName(StringRef Name); + +/// } + /// Try to parse a register name. The token must be an Identifier when called, /// and if it is a register name the token is eaten and the register number is /// returned. Otherwise return -1. /// int NDS32AsmParser::tryParseRegister() { + MCAsmParser &Parser = getParser(); + const AsmToken &Tok = Parser.getTok(); + if (Tok.isNot(AsmToken::Identifier)) return -1; + std::string lowerCase = Tok.getString().lower(); + unsigned RegNum = MatchRegisterName(lowerCase); + Parser.Lex(); // Eat identifier token. + return RegNum; } bool NDS32AsmParser:: ParseInstruction(ParseInstructionInfo &Info, StringRef Name, SMLoc NameLoc, OperandVector &Operands) { - return true; + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "ParseInstruction\n"); + + // Check if we have valid mnemonic + if (!mnemonicIsValid(Name, 0)) { + Parser.eatToEndOfStatement(); + return Error(NameLoc, "unknown instruction"); + } + // First operand in MCInst is instruction mnemonic. + Operands.push_back(NDS32Operand::CreateToken(Name, NameLoc, *this)); + + // Read the remaining operands. + if (getLexer().isNot(AsmToken::EndOfStatement)) { + // Read the first operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + + while (getLexer().is(AsmToken::Comma)) { + Parser.Lex(); // Eat the comma. + // Parse and remember the operand. + if (parseOperand(Operands, Name)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + } + } + if (getLexer().isNot(AsmToken::EndOfStatement)) { + SMLoc Loc = getLexer().getLoc(); + Parser.eatToEndOfStatement(); + return Error(Loc, "unexpected token in argument list"); + } + Parser.Lex(); // Consume the EndOfStatement. + return false; } bool NDS32AsmParser::ParseDirective(AsmToken DirectiveID) { @@ -539,7 +697,39 @@ MCStreamer &Out, uint64_t &ErrorInfo, bool MatchingInlineAsm) { - return true; + MCInst Inst; + unsigned MatchResult = + MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + + switch (MatchResult) { + case Match_Success: { + Inst.setLoc(IDLoc); + Out.EmitInstruction(Inst, getSTI()); + return false; + } + case Match_MissingFeature: + Error(IDLoc, "instruction requires a CPU feature not currently enabled"); + return true; + case Match_InvalidOperand: { + SMLoc ErrorLoc = IDLoc; + if (ErrorInfo != ~0ULL) { + if (ErrorInfo >= Operands.size()) + return Error(IDLoc, "too few operands for instruction"); + + ErrorLoc = Operands[ErrorInfo]->getStartLoc(); + if (ErrorLoc == SMLoc()) + ErrorLoc = IDLoc; + } + + return Error(ErrorLoc, "invalid operand for instruction"); + } + case Match_MnemonicFail: + return Error(IDLoc, "invalid instruction"); + case Match_RequiresNotInRegisterList: + return Error(IDLoc, "base register must not contain in register list"); + } + + llvm_unreachable("Implement any new match types added!"); } unsigned NDS32AsmParser::checkTargetMatchPredicate(MCInst &Inst) { @@ -550,6 +740,27 @@ } bool NDS32AsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { + MCAsmParser &Parser = getParser(); + DEBUG(dbgs() << "parseOperand\n"); + + switch (getLexer().getKind()) { + default: + Error(Parser.getTok().getLoc(), "unexpected token in operand"); + return true; + case AsmToken::Dollar: { + // Parse the register. + if (parseAnyRegister(Operands) != MatchOperand_NoMatch) + return false; + } + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Integer: + case AsmToken::String: { + OperandMatchResultTy ResTy = parseImm(Operands); + return ResTy != MatchOperand_Success; + } + } // switch(getLexer().getKind()) + return true; } Index: lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp =================================================================== --- lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp +++ lib/Target/NDS32/Disassembler/NDS32Disassembler.cpp @@ -189,6 +189,10 @@ unsigned RegNo, uint64_t Address, const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = getReg(Decoder, NDS32::GPRRegClassID, RegNo); + Inst.addOperand(MCOperand::createReg(Reg)); return MCDisassembler::Success; } @@ -196,7 +200,9 @@ unsigned RegNo, uint64_t Address, const void *Decoder) { - return MCDisassembler::Success; + if (RegNo > 7) + return MCDisassembler::Fail; + return DecodeGPRRegisterClass(Inst, RegNo, Address, Decoder); } static DecodeStatus DecodeJumpTarget(MCInst &Inst, @@ -327,6 +333,9 @@ unsigned Insn, uint64_t Address, const void *Decoder) { + int32_t Value = fieldFromInstruction(Insn, 0, 5); + int32_t Imm = SignExtend32<5>(Value); + Inst.addOperand(MCOperand::createImm(Imm)); return MCDisassembler::Success; } @@ -334,6 +343,9 @@ unsigned Insn, uint64_t Address, const void *Decoder) { + int32_t Value = fieldFromInstruction(Insn, 0, 11); + int32_t Imm = SignExtend32<11>(Value); + Inst.addOperand(MCOperand::createImm(Imm)); return MCDisassembler::Success; } @@ -341,6 +353,9 @@ unsigned Insn, uint64_t Address, const void *Decoder) { + int32_t Value = fieldFromInstruction(Insn, 0, 15); + int32_t Imm = SignExtend32<15>(Value); + Inst.addOperand(MCOperand::createImm(Imm)); return MCDisassembler::Success; } @@ -348,6 +363,9 @@ unsigned Insn, uint64_t Address, const void *Decoder) { + int32_t Value = fieldFromInstruction(Insn, 0, 20); + int32_t Imm = SignExtend32<20>(Value); + Inst.addOperand(MCOperand::createImm(Imm)); return MCDisassembler::Success; } Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -42,6 +42,8 @@ def imm5s : Operand, ImmLeaf= -(1 << 4) && Imm < (1 << 4); }]> { + let ParserMatchClass = Imm5sAsmOperand; + let DecoderMethod = "DecodeImm5s"; } /// imm11s predicate - Immediate in the range [-(1 << 10) , (1 << 10)]. @@ -52,6 +54,8 @@ def imm11s : Operand, ImmLeaf= -(1 << 10) && Imm < (1 << 10); }]> { + let ParserMatchClass = Imm11sAsmOperand; + let DecoderMethod = "DecodeImm11s"; } /// imm15s predicate - Immediate in the range [-(1 << 14) , (1 << 14)]. @@ -62,6 +66,8 @@ def imm15s : Operand, ImmLeaf= -(1 << 14) && Imm < (1 << 14); }]> { + let ParserMatchClass = Imm15sAsmOperand; + let DecoderMethod = "DecodeImm15s"; } /// imm20s predicate - Immediate in the range [-(1 << 19) , (1 << 19)]. @@ -72,6 +78,8 @@ def imm20s : Operand, ImmLeaf= -(1 << 19) && Imm < (1 << 19); }]> { + let ParserMatchClass = Imm20sAsmOperand; + let DecoderMethod = "DecodeImm20s"; } /// imm3u predicate - Immediate in the range [0 , (1 << 3)]. @@ -82,6 +90,7 @@ def imm3u : Operand, ImmLeaf= 0 && Imm < (1 << 3); }]> { + let ParserMatchClass = Imm3uAsmOperand; } /// imm5u predicate - Immediate in the range [0 , (1 << 5)]. @@ -92,6 +101,7 @@ def imm5u : Operand, ImmLeaf= 0 && Imm < (1 << 5); }]> { + let ParserMatchClass = Imm5uAsmOperand; } /// imm15u predicate - Immediate in the range [0 , (1 << 15)]. @@ -102,6 +112,7 @@ def imm15u : Operand, ImmLeaf= 0 && Imm < (1 << 15); }]> { + let ParserMatchClass = Imm15uAsmOperand; } /// imm20u predicate - Immediate in the range [0 , (1 << 20)]. @@ -112,6 +123,7 @@ def imm20u : Operand, ImmLeaf= 0 && Imm < (1 << 20); }]> { + let ParserMatchClass = Imm20uAsmOperand; } // Plus 1. Index: test/MC/NDS32/16-bit-alu.s =================================================================== --- /dev/null +++ test/MC/NDS32/16-bit-alu.s @@ -0,0 +1,23 @@ +! RUN: llvm-mc -triple nds32 -filetype=obj -o %t %s +! RUN: llvm-objdump -d -r -triple nds32 %t | FileCheck %s +alu: + add333 $r0, $r1, $r2 + sub333 $r3, $r4, $r5 + and33 $r6, $r7 + mul33 $r0, $r1 + or33 $r2, $r3 + xor33 $r4, $r5 + not33 $r6, $r7 + seb33 $r0, $r1 + seh33 $r2, $r3 + addi333 $r0, $r1, 1 +! CHECK: 98 0a add333 $r0, $r1, $r2 +! CHECK: 9a e5 sub333 $r3, $r4, $r5 +! CHECK: ff be and33 $r6, $r7 +! CHECK: fe 0c mul33 $r0, $r1 +! CHECK: fe 9f or33 $r2, $r3 +! CHECK: ff 2d xor33 $r4, $r5 +! CHECK: ff bb not33 $r6, $r7 +! CHECK: 96 0a seb33 $r0, $r1 +! CHECK: 96 9b seh33 $r2, $r3 +! CHECK: 9c 09 addi333 $r0, $r1, 1 Index: test/MC/NDS32/alu-insns.s =================================================================== --- /dev/null +++ test/MC/NDS32/alu-insns.s @@ -0,0 +1,89 @@ +! RUN: llvm-mc -triple nds32 -filetype=obj -o %t %s +! RUN: llvm-objdump -d -r -triple nds32 %t | FileCheck %s +alu: + add $sp, $fp, $lp + sub $r0, $r1, $r2 + and $r3, $r4, $r5 + or $r6, $r7, $r8 + sll $r9, $r10, $r11 + srl $r12, $r13, $r14 + sra $r15, $r16, $r17 + xor $r18, $r19, $r20 + slt $r21, $r22, $r23 + slts $r24, $r25, $r26 + rotr $r0, $r1, $gp + mul $r2, $r3, $r4 + maddr32 $r5, $r6, $r7 + msubr32 $r8, $r9, $r10 + nor $r11, $r12, $r13 + bitc $r14, $r15, $r16 + seb $r17, $r18 + seh $r20, $r21 + divr $r23, $r24, $r25, $r26 + divsr $r27, $fp, $gp, $lp + clz $sp, $r1 +! CHECK: 41 fe 78 00 add $sp, $fp, $lp +! CHECK: 40 00 88 01 sub $r0, $r1, $r2 +! CHECK: 40 32 14 02 and $r3, $r4, $r5 +! CHECK: 40 63 a0 04 or $r6, $r7, $r8 +! CHECK: 40 95 2c 0c sll $r9, $r10, $r11 +! CHECK: 40 c6 b8 0d srl $r12, $r13, $r14 +! CHECK: 40 f8 44 0e sra $r15, $r16, $r17 +! CHECK: 41 29 d0 03 xor $r18, $r19, $r20 +! CHECK: 41 5b 5c 06 slt $r21, $r22, $r23 +! CHECK: 41 8c e8 07 slts $r24, $r25, $r26 +! CHECK: 40 00 f4 0f rotr $r0, $r1, $gp +! CHECK: 42 21 90 24 mul $r2, $r3, $r4 +! CHECK: 42 53 1c 73 maddr32 $r5, $r6, $r7 +! CHECK: 42 84 a8 75 msubr32 $r8, $r9, $r10 +! CHECK: 40 b6 34 05 nor $r11, $r12, $r13 +! CHECK: 40 e7 c0 12 bitc $r14, $r15, $r16 +! CHECK: 41 19 00 10 seb $r17, $r18 +! CHECK: 41 4a 80 11 seh $r20, $r21 +! CHECK: 41 7c eb 17 divr $r23, $r24, $r25, $r26 +! CHECK: 41 be fb 96 divsr $r27, $fp, $gp, $lp +! CHECK: 43 f0 80 07 clz $sp, $r1 + +alu_imm: + addi $sp, $fp, -15 + subri $r0, $r1, 1 + andi $r3, $r4, 2 + ori $r6, $r7, 3 + slli $r9, $r10, 4 + srli $r12, $r13, 5 + srai $r15, $r16, 6 + xori $r18, $r19, 7 + slti $r21, $r22, 8 + sltsi $r24, $r25, 9 +! CHECK: 51 fe 7f f1 addi $sp, $fp, -15 +! CHECK: 52 00 80 01 subri $r0, $r1, 1 +! CHECK: 54 32 00 02 andi $r3, $r4, 2 +! CHECK: 58 63 80 03 ori $r6, $r7, 3 +! CHECK: 40 95 10 08 slli $r9, $r10, 4 +! CHECK: 40 c6 94 09 srli $r12, $r13, 5 +! CHECK: 40 f8 18 0a srai $r15, $r16, 6 +! CHECK: 57 29 80 07 xori $r18, $r19, 7 +! CHECK: 5d 5b 00 08 slti $r21, $r22, 8 +! CHECK: 5f 8c 80 09 sltsi $r24, $r25, 9 + +alu_shift: + add_slli $r0, $r1, $r2, 1 + add_srli $r3, $r4, $r5, 2 + sub_slli $r6, $r7, $r8, 3 + sub_srli $r9, $r10, $r11, 4 + and_slli $r12, $r13, $r14, 5 + and_srli $r15, $r16, $r17, 6 + xor_slli $r18, $r19, $r20, 7 + xor_srli $r21, $r22, $r23, 8 + or_slli $r24, $r25, $r26, 9 + or_srli $sp, $lp, $gp, 10 +! CHECK: 40 00 88 20 add_slli $r0, $r1, $r2, 1 +! CHECK: 40 32 14 5c add_srli $r3, $r4, $r5, 2 +! CHECK: 40 63 a0 61 sub_slli $r6, $r7, $r8, 3 +! CHECK: 40 95 2c 9d sub_srli $r9, $r10, $r11, 4 +! CHECK: 40 c6 b8 a2 and_slli $r12, $r13, $r14, 5 +! CHECK: 40 f8 44 de and_srli $r15, $r16, $r17, 6 +! CHECK: 41 29 d0 e3 xor_slli $r18, $r19, $r20, 7 +! CHECK: 41 5b 5d 1f xor_srli $r21, $r22, $r23, 8 +! CHECK: 41 8c e9 24 or_slli $r24, $r25, $r26, 9 +! CHECK: 41 ff 75 55 or_srli $sp, $lp, $gp, 10 Index: test/MC/NDS32/lit.local.cfg =================================================================== --- /dev/null +++ test/MC/NDS32/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'NDS32' in config.root.targets: + config.unsupported = True