diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp index 8ac1cdf0a7a9ce..5424c8154d5555 100644 --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -703,7 +703,9 @@ struct RISCVOperand final : public MCParsedAsmOperand { bool isUImm6() const { return IsUImm<6>(); } bool isUImm7() const { return IsUImm<7>(); } bool isUImm8() const { return IsUImm<8>(); } + bool isUImm16() const { return IsUImm<16>(); } bool isUImm20() const { return IsUImm<20>(); } + bool isUImm32() const { return IsUImm<32>(); } bool isUImm8GE32() const { int64_t Imm; @@ -3055,17 +3057,50 @@ bool isValidInsnFormat(StringRef Format, bool AllowC) { /// parseDirectiveInsn /// ::= .insn [ format encoding, (operands (, operands)*) ] +/// ::= .insn [ length, value ] +/// ::= .insn [ value ] bool RISCVAsmParser::parseDirectiveInsn(SMLoc L) { MCAsmParser &Parser = getParser(); + bool AllowC = getSTI().hasFeature(RISCV::FeatureStdExtC) || + getSTI().hasFeature(RISCV::FeatureStdExtZca); + // Expect instruction format as identifier. StringRef Format; SMLoc ErrorLoc = Parser.getTok().getLoc(); - if (Parser.parseIdentifier(Format)) - return Error(ErrorLoc, "expected instruction format"); + if (Parser.parseIdentifier(Format)) { + // Try parsing .insn [length], value + int64_t Length = 0; + int64_t Value = 0; + if (Parser.parseIntToken( + Value, "expected instruction format or an integer constant")) + return true; + if (Parser.parseOptionalToken(AsmToken::Comma)) { + Length = Value; + if (Parser.parseIntToken(Value, "expected an integer constant")) + return true; + } + + // TODO: Add support for long instructions + int64_t RealLength = (Value & 3) == 3 ? 4 : 2; + if (!isUIntN(RealLength * 8, Value)) + return Error(ErrorLoc, "invalid operand for instruction"); + if (RealLength == 2 && !AllowC) + return Error(ErrorLoc, "compressed instructions are not allowed"); + if (Length != 0 && Length != RealLength) + return Error(ErrorLoc, "instruction length mismatch"); + + if (getParser().parseEOL("invalid operand for instruction")) { + getParser().eatToEndOfStatement(); + return true; + } + + emitToStreamer(getStreamer(), MCInstBuilder(RealLength == 2 ? RISCV::Insn16 + : RISCV::Insn32) + .addImm(Value)); + return false; + } - bool AllowC = getSTI().hasFeature(RISCV::FeatureStdExtC) || - getSTI().hasFeature(RISCV::FeatureStdExtZca); if (!isValidInsnFormat(Format, AllowC)) return Error(ErrorLoc, "invalid instruction format"); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h index 550904516ac8e8..cf83bd977939e5 100644 --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -279,6 +279,8 @@ enum OperandType : unsigned { OPERAND_UIMM9_LSB000, OPERAND_UIMM10_LSB00_NONZERO, OPERAND_UIMM12, + OPERAND_UIMM16, + OPERAND_UIMM32, OPERAND_ZERO, OPERAND_SIMM5, OPERAND_SIMM5_PLUS1, diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index 4cdf08a46f285b..075aaae2ce5074 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -233,6 +233,8 @@ def uimm7_opcode : RISCVUImmOp<7> { } def uimm7 : RISCVUImmOp<7>; def uimm8 : RISCVUImmOp<8>; +def uimm16 : RISCVUImmOp<16>; +def uimm32 : RISCVUImmOp<32>; def simm12 : RISCVSImmLeafOp<12> { let MCOperandPredicate = [{ int64_t Imm; @@ -1120,6 +1122,12 @@ def InsnS : DirectiveInsnS<(outs), (ins uimm7_opcode:$opcode, uimm3:$funct3, AnyReg:$rs2, AnyReg:$rs1, simm12:$imm12), "$opcode, $funct3, $rs2, ${imm12}(${rs1})">; +def Insn32 : RVInst<(outs), (ins uimm32:$value), "", "", [], InstFormatOther> { + bits<32> value; + + let Inst{31-0} = value; + let AsmString = ".insn 0x4, $value"; +} } // Use InstAliases to match these so that we can combine the insn and format diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td index 458d081763e931..82eeef0ae10a3f 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td @@ -801,6 +801,12 @@ def InsnCJ : DirectiveInsnCJ<(outs), (ins uimm2_opcode:$opcode, uimm3:$funct3, simm12_lsb0:$imm11), "$opcode, $funct3, $imm11">; +def Insn16 : RVInst16<(outs), (ins uimm16:$value), "", "", [], InstFormatOther> { + bits<16> value; + + let Inst{15-0} = value; + let AsmString = ".insn 0x2, $value"; +} } // Use InstAliases to match these so that we can combine the insn and format diff --git a/llvm/test/MC/RISCV/insn-invalid.s b/llvm/test/MC/RISCV/insn-invalid.s index 32ebd6867377c2..d6fabea4e17016 100644 --- a/llvm/test/MC/RISCV/insn-invalid.s +++ b/llvm/test/MC/RISCV/insn-invalid.s @@ -23,3 +23,11 @@ # Make fake mnemonics we use to match these in the tablegened asm match table isn't exposed. .insn_i 0x13, 0, a0, a1, 13, 14 # CHECK: :[[@LINE]]:1: error: unknown directive + +.insn . # CHECK: :[[@LINE]]:7: error: expected instruction format or an integer constant +.insn 0x2, # CHECK: :[[@LINE]]:12: error: expected an integer constant +.insn 0x2, 0xffff # CHECK: :[[@LINE]]:7: error: instruction length mismatch +.insn 0x2, 0xffffffff # CHECK: :[[@LINE]]:7: error: instruction length mismatch +.insn 0xffffffffff # CHECK: :[[@LINE]]:7: error: invalid operand for instruction +.insn 0x0010 # CHECK: :[[@LINE]]:7: error: compressed instructions are not allowed +.insn 0x4, 0x13, 0 # CHECK: :[[@LINE]]:16: error: invalid operand for instruction diff --git a/llvm/test/MC/RISCV/insn.s b/llvm/test/MC/RISCV/insn.s index 4eb9a8a7ebf258..b95c3b87b442f2 100644 --- a/llvm/test/MC/RISCV/insn.s +++ b/llvm/test/MC/RISCV/insn.s @@ -154,3 +154,13 @@ target: # CHECK-ASM: encoding: [0x03,0xd3,0x03,0x80] # CHECK-OBJ: lhu t1, -0x800(t2) .insn i LOAD, 0x5, x6, %lo(2048)(x7) + +# CHECK-ASM: .insn 0x4, 19 +# CHECK-ASM: encoding: [0x13,0x00,0x00,0x00] +# CHECK-OBJ: addi zero, zero, 0x0 +.insn 0x13 + +# CHECK-ASM: .insn 0x4, 19 +# CHECK-ASM: encoding: [0x13,0x00,0x00,0x00] +# CHECK-OBJ: addi zero, zero, 0x0 +.insn 0x4, 0x13 diff --git a/llvm/test/MC/RISCV/insn_c-invalid.s b/llvm/test/MC/RISCV/insn_c-invalid.s index c983d32e7fe97e..3b424b2a9fd329 100644 --- a/llvm/test/MC/RISCV/insn_c-invalid.s +++ b/llvm/test/MC/RISCV/insn_c-invalid.s @@ -24,3 +24,4 @@ ## Make fake mnemonics we use to match these in the tablegened asm match table isn't exposed. .insn_cr 2, 9, a0, a1 # CHECK: :[[#@LINE]]:1: error: unknown directive +.insn 0xfffffff0 # CHECK: :[[@LINE]]:7: error: invalid operand for instruction diff --git a/llvm/test/MC/RISCV/insn_c.s b/llvm/test/MC/RISCV/insn_c.s index e1b3003e0200d2..19169e8b08c94c 100644 --- a/llvm/test/MC/RISCV/insn_c.s +++ b/llvm/test/MC/RISCV/insn_c.s @@ -80,3 +80,13 @@ target: # CHECK-ASM: encoding: [0bAAAAAA01,0b101AAAAA] # CHECK-OBJ: c.j 0x0 .insn cj 1, 5, target + +# CHECK-ASM: .insn 0x2, 1 +# CHECK-ASM: encoding: [0x01,0x00] +# CHECK-OBJ: c.nop +.insn 0x0001 + +# CHECK-ASM: .insn 0x2, 1 +# CHECK-ASM: encoding: [0x01,0x00] +# CHECK-OBJ: c.nop +.insn 0x2, 0x0001