diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp --- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -172,6 +172,7 @@ OperandMatchResultTy parseVTypeI(OperandVector &Operands); OperandMatchResultTy parseMaskReg(OperandVector &Operands); OperandMatchResultTy parseInsnDirectiveOpcode(OperandVector &Operands); + OperandMatchResultTy parseInsnCDirectiveOpcode(OperandVector &Operands); OperandMatchResultTy parseGPRAsFPR(OperandVector &Operands); OperandMatchResultTy parseFRMArg(OperandVector &Operands); OperandMatchResultTy parseFenceArg(OperandVector &Operands); @@ -374,6 +375,13 @@ RISCVMCRegisterClasses[RISCV::FPR64RegClassID].contains(Reg.RegNum) || RISCVMCRegisterClasses[RISCV::VRRegClassID].contains(Reg.RegNum)); } + bool isAnyRegC() const { + return Kind == KindTy::Register && + (RISCVMCRegisterClasses[RISCV::GPRCRegClassID].contains( + Reg.RegNum) || + RISCVMCRegisterClasses[RISCV::FPR64CRegClassID].contains( + Reg.RegNum)); + } bool isImm() const override { return Kind == KindTy::Immediate; } bool isMem() const override { return false; } bool isSystemRegister() const { return Kind == KindTy::SystemRegister; } @@ -569,9 +577,11 @@ 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 isRnumArg() const { int64_t Imm; @@ -1250,10 +1260,16 @@ "immediate must be one of"); 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_InvalidSImm5: return generateImmOutOfRangeError(Operands, ErrorInfo, -(1 << 4), (1 << 4) - 1); @@ -1539,6 +1555,67 @@ return MatchOperand_ParseFail; } +OperandMatchResultTy +RISCVAsmParser::parseInsnCDirectiveOpcode(OperandVector &Operands) { + SMLoc S = getLoc(); + SMLoc E; + const MCExpr *Res; + + switch (getLexer().getKind()) { + default: + return MatchOperand_NoMatch; + case AsmToken::LParen: + case AsmToken::Minus: + case AsmToken::Plus: + case AsmToken::Exclaim: + case AsmToken::Tilde: + case AsmToken::Integer: + case AsmToken::String: { + if (getParser().parseExpression(Res, E)) + return MatchOperand_ParseFail; + + auto *CE = dyn_cast(Res); + if (CE) { + int64_t Imm = CE->getValue(); + if (Imm >= 0 && Imm <= 2) { + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); + return MatchOperand_Success; + } + } + + break; + } + case AsmToken::Identifier: { + StringRef Identifier; + if (getParser().parseIdentifier(Identifier)) + return MatchOperand_ParseFail; + + unsigned Opcode; + if (Identifier == "C0") + Opcode = 0; + else if (Identifier == "C1") + Opcode = 1; + else if (Identifier == "C2") + Opcode = 2; + else + break; + + Res = MCConstantExpr::create(Opcode, getContext()); + E = SMLoc::getFromPointer(S.getPointer() + Identifier.size()); + Operands.push_back(RISCVOperand::createImm(Res, S, E, isRV64())); + return MatchOperand_Success; + } + case AsmToken::Percent: { + // Discard operand with modifier. + break; + } + } + + Error(S, "opcode must be a valid opcode name or an immediate in the range " + "[0, 2]"); + return MatchOperand_ParseFail; +} + OperandMatchResultTy RISCVAsmParser::parseCSRSystemRegister(OperandVector &Operands) { SMLoc S = getLoc(); @@ -2472,6 +2549,13 @@ return false; } +bool isValidInsnFormat(StringRef Format, bool AllowC) { + return StringSwitch(Format) + .Cases("r", "r4", "i", "b", "sb", "u", "j", "uj", "s", true) + .Cases("cr", "ci", "ciw", "css", "cl", "cs", "ca", "cb", "cj", AllowC) + .Default(false); +} + /// parseDirectiveInsn /// ::= .insn [ format encoding, (operands (, operands)*) ] bool RISCVAsmParser::parseDirectiveInsn(SMLoc L) { @@ -2483,9 +2567,9 @@ if (Parser.parseIdentifier(Format)) return Error(ErrorLoc, "expected instruction format"); - if (Format != "r" && Format != "r4" && Format != "i" && Format != "b" && - Format != "sb" && Format != "u" && Format != "j" && Format != "uj" && - Format != "s") + bool AllowC = getSTI().hasFeature(RISCV::FeatureStdExtC) || + getSTI().hasFeature(RISCV::FeatureExtZca); + if (!isValidInsnFormat(Format, AllowC)) return Error(ErrorLoc, "invalid instruction format"); std::string FormatName = (".insn_" + Format).str(); diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h --- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -249,6 +249,7 @@ OPERAND_UIMM7, OPERAND_UIMM7_LSB00, OPERAND_UIMM8_LSB00, + OPERAND_UIMM8, OPERAND_UIMM8_LSB000, OPERAND_UIMM9_LSB000, OPERAND_UIMM10_LSB00_NONZERO, diff --git a/llvm/lib/Target/RISCV/RISCVInstrFormatsC.td b/llvm/lib/Target/RISCV/RISCVInstrFormatsC.td --- a/llvm/lib/Target/RISCV/RISCVInstrFormatsC.td +++ b/llvm/lib/Target/RISCV/RISCVInstrFormatsC.td @@ -229,3 +229,169 @@ let Inst{4-2} = rs2; let Inst{1-0} = opcode; } + +//===----------------------------------------------------------------------===// +// Instruction classes for .insn directives +//===----------------------------------------------------------------------===// + +class DirectiveInsnCR + : RVInst16 { + bits<2> opcode; + bits<4> funct4; + + bits<5> rs2; + bits<5> rd; + + let Inst{15-12} = funct4; + let Inst{11-7} = rd; + let Inst{6-2} = rs2; + let Inst{1-0} = opcode; + + let AsmString = ".insn cr " # argstr; +} + +class DirectiveInsnCI + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<6> imm6; + bits<5> rd; + + let Inst{15-13} = funct3; + let Inst{12} = imm6{5}; + let Inst{11-7} = rd; + let Inst{6-2} = imm6{4-0}; + let Inst{1-0} = opcode; + + let AsmString = ".insn ci " # argstr; +} + +class DirectiveInsnCIW + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<8> imm8; + bits<3> rd; + + let Inst{15-13} = funct3; + let Inst{12-5} = imm8; + let Inst{4-2} = rd; + let Inst{1-0} = opcode; + + let AsmString = ".insn ciw " # argstr; +} + +class DirectiveInsnCSS + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<6> imm6; + bits<5> rs2; + + let Inst{15-13} = funct3; + let Inst{12-7} = imm6; + let Inst{6-2} = rs2; + let Inst{1-0} = opcode; + + let AsmString = ".insn css " # argstr; +} + +class DirectiveInsnCL + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<5> imm5; + bits<3> rd; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{12-10} = imm5{4-2}; + let Inst{9-7} = rs1; + let Inst{6-5} = imm5{1-0}; + let Inst{4-2} = rd; + let Inst{1-0} = opcode; + + let AsmString = ".insn cl " # argstr; +} + +class DirectiveInsnCS + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<5> imm5; + bits<3> rs2; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{12-10} = imm5{4-2}; + let Inst{9-7} = rs1; + let Inst{6-5} = imm5{1-0}; + let Inst{4-2} = rs2; + let Inst{1-0} = opcode; + + let AsmString = ".insn cs " # argstr; +} + +class DirectiveInsnCA + : RVInst16 { + bits<2> opcode; + bits<6> funct6; + bits<2> funct2; + + bits<3> rd; + bits<3> rs2; + + let Inst{15-10} = funct6; + let Inst{9-7} = rd; + let Inst{6-5} = funct2; + let Inst{4-2} = rs2; + let Inst{1-0} = opcode; + + let AsmString = ".insn ca " # argstr; +} + +class DirectiveInsnCB + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<8> imm8; + bits<3> rs1; + + let Inst{15-13} = funct3; + let Inst{12} = imm8{7}; + let Inst{11-10} = imm8{3-2}; + let Inst{9-7} = rs1; + let Inst{6-5} = imm8{6-5}; + let Inst{4-3} = imm8{1-0}; + let Inst{2} = imm8{4}; + let Inst{1-0} = opcode; + + let AsmString = ".insn cb " # argstr; +} + +class DirectiveInsnCJ + : RVInst16 { + bits<2> opcode; + bits<3> funct3; + + bits<11> imm11; + + let Inst{15-13} = funct3; + let Inst{12} = imm11{10}; + let Inst{11} = imm11{3}; + let Inst{10-9} = imm11{8-7}; + let Inst{8} = imm11{9}; + let Inst{7} = imm11{5}; + let Inst{6} = imm11{6}; + let Inst{5-3} = imm11{2-0}; + let Inst{2} = imm11{4}; + let Inst{1-0} = opcode; + + let AsmString = ".insn cj " # argstr; +} diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -1672,7 +1672,9 @@ CASE_OPERAND_UIMM(3) CASE_OPERAND_UIMM(4) CASE_OPERAND_UIMM(5) + CASE_OPERAND_UIMM(6) CASE_OPERAND_UIMM(7) + CASE_OPERAND_UIMM(8) CASE_OPERAND_UIMM(12) CASE_OPERAND_UIMM(20) // clang-format on diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -211,6 +211,13 @@ let OperandNamespace = "RISCVOp"; } +def uimm4 : Operand { + let ParserMatchClass = UImmAsmOperand<4>; + let DecoderMethod = "decodeUImmOperand<4>"; + let OperandType = "OPERAND_UIMM4"; + let OperandNamespace = "RISCVOp"; +} + def uimm5 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = UImmAsmOperand<5>; let DecoderMethod = "decodeUImmOperand<5>"; @@ -246,6 +253,13 @@ let OperandNamespace = "RISCVOp"; } +def uimm8 : Operand { + let ParserMatchClass = UImmAsmOperand<8>; + let DecoderMethod = "decodeUImmOperand<8>"; + let OperandType = "OPERAND_UIMM8"; + let OperandNamespace = "RISCVOp"; +} + def simm12 : Operand, ImmLeaf(Imm);}]> { let ParserMatchClass = SImmAsmOperand<12>; let EncoderMethod = "getImmOpValue"; diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td --- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td @@ -236,6 +236,20 @@ let OperandType = "OPERAND_PCREL"; } +def InsnCDirectiveOpcode : AsmOperandClass { + let Name = "InsnCDirectiveOpcode"; + let ParserMethod = "parseInsnCDirectiveOpcode"; + let RenderMethod = "addImmOperands"; + let PredicateMethod = "isImm"; +} + +def uimm2_opcode : Operand { + let ParserMatchClass = InsnCDirectiveOpcode; + let DecoderMethod = "decodeUImmOperand<2>"; + let OperandType = "OPERAND_UIMM2"; + let OperandNamespace = "RISCVOp"; +} + //===----------------------------------------------------------------------===// // Instruction Class Templates //===----------------------------------------------------------------------===// @@ -749,6 +763,100 @@ } } // EmitPriority = 0 +//===----------------------------------------------------------------------===// +// .insn directive instructions +//===----------------------------------------------------------------------===// + +def AnyRegCOperand : AsmOperandClass { + let Name = "AnyRegCOperand"; + let RenderMethod = "addRegOperands"; + let PredicateMethod = "isAnyRegC"; +} + +def AnyRegC : Operand { + let OperandType = "OPERAND_REGISTER"; + let ParserMatchClass = AnyRegCOperand; +} + +// isCodeGenOnly = 1 to hide them from the tablegened assembly parser. +let isCodeGenOnly = 1, hasSideEffects = 1, mayLoad = 1, mayStore = 1, + hasNoSchedulingInfo = 1, Predicates = [HasStdExtCOrZca] in { +def InsnCR : DirectiveInsnCR<(outs AnyReg:$rd), (ins uimm2_opcode:$opcode, + uimm4:$funct4, + AnyReg:$rs2), + "$opcode, $funct4, $rd, $rs2">; +def InsnCI : DirectiveInsnCI<(outs AnyRegC:$rd), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + simm6:$imm6), + "$opcode, $funct3, $rd, $imm6">; +def InsnCIW : DirectiveInsnCIW<(outs AnyRegC:$rd), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + uimm8:$imm8), + "$opcode, $funct3, $rd, $imm8">; +def InsnCSS : DirectiveInsnCSS<(outs), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + AnyReg:$rs2, + uimm6:$imm6), + "$opcode, $funct3, $rs2, $imm6">; +def InsnCL : DirectiveInsnCL<(outs AnyRegC:$rd), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + AnyRegC:$rs1, + uimm5:$imm5), + "$opcode, $funct3, $rd, ${imm5}(${rs1})">; +def InsnCS : DirectiveInsnCS<(outs), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + AnyRegC:$rs2, + AnyRegC:$rs1, + uimm5:$imm5), + "$opcode, $funct3, $rs2, ${imm5}(${rs1})">; +def InsnCA : DirectiveInsnCA<(outs AnyRegC:$rd), (ins uimm2_opcode:$opcode, + uimm6:$funct6, + uimm2:$funct2, + AnyRegC:$rs2), + "$opcode, $funct6, $funct2, $rd, $rs2">; +def InsnCB : DirectiveInsnCB<(outs), (ins uimm2_opcode:$opcode, uimm3:$funct3, + AnyRegC:$rs1, + simm9_lsb0:$imm8), + "$opcode, $funct3, $rs1, $imm8">; +def InsnCJ : DirectiveInsnCJ<(outs), (ins uimm2_opcode:$opcode, + uimm3:$funct3, + simm12_lsb0:$imm11), + "$opcode, $funct3, $imm11">; +} + +// Use InstAliases to match these so that we can combine the insn and format +// into a mnemonic to use as the key for the tablegened asm matcher table. The +// parser will take care of creating these fake mnemonics and will only do it +// for known formats. +let EmitPriority = 0, Predicates = [HasStdExtCOrZca] in { +def : InstAlias<".insn_cr $opcode, $funct4, $rd, $rs2", + (InsnCR AnyReg:$rd, uimm2_opcode:$opcode, uimm4:$funct4, + AnyReg:$rs2)>; +def : InstAlias<".insn_ci $opcode, $funct3, $rd, $imm6", + (InsnCI AnyRegC:$rd, uimm2_opcode:$opcode, uimm3:$funct3, + simm6:$imm6)>; +def : InstAlias<".insn_ciw $opcode, $funct3, $rd, $imm8", + (InsnCIW AnyRegC:$rd, uimm2_opcode:$opcode, uimm3:$funct3, + uimm8:$imm8)>; +def : InstAlias<".insn_css $opcode, $funct3, $rs2, $imm6", + (InsnCSS uimm2_opcode:$opcode, uimm3:$funct3, AnyReg:$rs2, + uimm6:$imm6)>; +def : InstAlias<".insn_cl $opcode, $funct3, $rd, ${imm5}(${rs1})", + (InsnCL AnyRegC:$rd, uimm2_opcode:$opcode, uimm3:$funct3, + AnyRegC:$rs1, uimm5:$imm5)>; +def : InstAlias<".insn_cs $opcode, $funct3, $rs2, ${imm5}(${rs1})", + (InsnCS uimm2_opcode:$opcode, uimm3:$funct3, AnyRegC:$rs2, + AnyRegC:$rs1, uimm5:$imm5)>; +def : InstAlias<".insn_ca $opcode, $funct6, $funct2, $rd, $rs2", + (InsnCA AnyRegC:$rd, uimm2_opcode:$opcode, uimm6:$funct6, + uimm2:$funct2, AnyRegC:$rs2)>; +def : InstAlias<".insn_cb $opcode, $funct3, $rs1, $imm8", + (InsnCB uimm2_opcode:$opcode, uimm3:$funct3, AnyRegC:$rs1, + simm9_lsb0:$imm8)>; +def : InstAlias<".insn_cj $opcode, $funct3, $imm11", + (InsnCJ uimm2_opcode:$opcode, uimm3:$funct3, simm12_lsb0:$imm11)>; +} + //===----------------------------------------------------------------------===/i // Compress Instruction tablegen backend. //===----------------------------------------------------------------------===// diff --git a/llvm/test/MC/RISCV/insn_c-invalid.s b/llvm/test/MC/RISCV/insn_c-invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/insn_c-invalid.s @@ -0,0 +1,26 @@ +# RUN: not llvm-mc -triple riscv32 -mattr=+c < %s 2>&1 | FileCheck %s + +# Too many operands +.insn ci 1, 0, a0, 13, 14 # CHECK: :[[#@LINE]]:25: error: invalid operand for instruction +.insn cr 2, 9, a0, a1, a2 # CHECK: :[[#@LINE]]:25: error: invalid operand for instruction + +## Too few operands +.insn ci 1, 0, a0 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction +.insn cr 2, 9, a0 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction + +.insn cr 2, 9, a0, 13 # CHECK: :[[#@LINE]]:21: error: invalid operand for instruction +.insn ci 1, 0, a0, a1 # CHECK: :[[#@LINE]]:21: error: immediate must be an integer in the range [-32, 31] + +.insn cq 0x13, 0, a0, a1, 13, 14 # CHECK: :[[#@LINE]]:7: error: invalid instruction format + +# Invalid immediate +.insn ci 3, 0, a0, 13 # CHECK: :[[#@LINE]]:11: error: opcode must be a valid opcode name or an immediate in the range [0, 2] +.insn cr 2, 16, a0, a1 # CHECK: :[[#@LINE]]:14: error: immediate must be an integer in the range [0, 15] +.insn ciw 0, 0, a0, 256 # CHECK: :[[#@LINE]]:21: error: immediate must be an integer in the range [0, 255] + +## Unrecognized opcode name +.insn cr C3, 9, a0, a1 # CHECK: :[[#@LINE]]:10: error: opcode must be a valid opcode name or an immediate in the range [0, 2] + +## 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 + diff --git a/llvm/test/MC/RISCV/insn_c.s b/llvm/test/MC/RISCV/insn_c.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/RISCV/insn_c.s @@ -0,0 +1,72 @@ +# RUN: llvm-mc %s -triple=riscv32 -mattr=+f,+c -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-ASM %s +# RUN: llvm-mc %s -triple riscv64 -mattr=+f,+c -riscv-no-aliases -show-encoding \ +# RUN: | FileCheck -check-prefix=CHECK-ASM %s +# RUN: llvm-mc -filetype=obj -triple=riscv32 -mattr=+f,+c < %s \ +# RUN: | llvm-objdump --mattr=+f,+c -M no-aliases -d -r - \ +# RUN: | FileCheck -check-prefix=CHECK-OBJ %s +# RUN: llvm-mc -filetype=obj -triple=riscv64 -mattr=+f,+c < %s \ +# RUN: | llvm-objdump --mattr=+f,+c -M no-aliases -d -r - \ +# RUN: | FileCheck -check-prefix=CHECK-OBJ %s + +target: + +# CHECK-ASM: .insn cr 2, 9, a0, a1 +# CHECK-ASM: encoding: [0x2e,0x95] +# CHECK-OBJ: c.add a0, a1 +.insn cr 2, 9, a0, a1 + +# CHECK-ASM: .insn cr 2, 9, a0, a1 +# CHECK-ASM: encoding: [0x2e,0x95] +# CHECK-OBJ: c.add a0, a1 +.insn cr C2, 9, a0, a1 + +# CHECK-ASM: .insn ci 1, 0, a0, 13 +# CHECK-ASM: encoding: [0x35,0x05] +# CHECK-OBJ: c.addi a0, 13 +.insn ci 1, 0, a0, 13 + +# CHECK-ASM: .insn ci 1, 0, a0, 13 +# CHECK-ASM: encoding: [0x35,0x05] +# CHECK-OBJ: c.addi a0, 13 +.insn ci C1, 0, a0, 13 + +# CHECK-ASM: .insn ciw 0, 0, a0, 13 +# CHECK-ASM: encoding: [0xa8,0x01] +# CHECK-OBJ: c.addi4spn a0, sp, 200 +.insn ciw 0, 0, a0, 13 + +# CHECK-ASM: .insn ciw 0, 0, a0, 13 +# CHECK-ASM: encoding: [0xa8,0x01] +# CHECK-OBJ: c.addi4spn a0, sp, 200 +.insn ciw C0, 0, a0, 13 + +# CHECK-ASM: .insn css 2, 6, a0, 13 +# CHECK-ASM: encoding: [0xaa,0xc6] +# CHECK-OBJ: c.swsp a0, 76(sp) +.insn css 2, 6, a0, 13 + +# CHECK-ASM: .insn cl 0, 2, a0, 13 +# CHECK-ASM: encoding: [0xa8,0x4d] +# CHECK-OBJ: c.lw a0, 88(a1) +.insn cl 0, 2, a0, 13(a1) + +# CHECK-ASM: .insn cs 0, 6, a0, 13 +# CHECK-ASM: encoding: [0xa8,0xcd] +# CHECK-OBJ: c.sw a0, 88(a1) +.insn cs 0, 6, a0, 13(a1) + +# CHECK-ASM: .insn ca 1, 35, 0, a0, a1 +# CHECK-ASM: encoding: [0x0d,0x8d] +# CHECK-OBJ: c.sub a0, a1 +.insn ca 1, 35, 0, a0, a1 + +# CHECK-ASM: .insn cb 1, 6, a0, target +# CHECK-ASM: encoding: [0x01'A',0xc1'A'] +# CHECK-OBJ: c.beqz a0, 0x0 +.insn cb 1, 6, a0, target + +# CHECK-ASM: .insn cj 1, 5, target +# CHECK-ASM: encoding: [0bAAAAAA01,0b101AAAAA] +# CHECK-OBJ: c.j 0x0 +.insn cj 1, 5, target