I think the failure was caused by a mistake in an earlier patch.
Original commit message:
We've supported .insn for non-compressed for a while. This finishes the compressed supported.
Differential Revision: https://reviews.llvm.org/D146663
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);
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; }
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;
"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);
}
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<MCConstantExpr>(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();
const MCExpr *Res;
return false;
}
+bool isValidInsnFormat(StringRef Format, bool AllowC) {
+ return StringSwitch<bool>(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) {
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();
OPERAND_UIMM7,
OPERAND_UIMM7_LSB00,
OPERAND_UIMM8_LSB00,
+ OPERAND_UIMM8,
OPERAND_UIMM8_LSB000,
OPERAND_UIMM9_LSB000,
OPERAND_UIMM10_LSB00_NONZERO,
let Inst{4-2} = rs2;
let Inst{1-0} = opcode;
}
+
+//===----------------------------------------------------------------------===//
+// Instruction classes for .insn directives
+//===----------------------------------------------------------------------===//
+
+class DirectiveInsnCR<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCR> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCI> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCIW> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCSS> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCL> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCS> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCA> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCB> {
+ 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<dag outs, dag ins, string argstr>
+ : RVInst16<outs, ins, "", "", [], InstFormatCJ> {
+ 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;
+}
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
let OperandNamespace = "RISCVOp";
}
+def uimm4 : Operand<XLenVT> {
+ let ParserMatchClass = UImmAsmOperand<4>;
+ let DecoderMethod = "decodeUImmOperand<4>";
+ let OperandType = "OPERAND_UIMM4";
+ let OperandNamespace = "RISCVOp";
+}
+
def uimm5 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isUInt<5>(Imm);}]> {
let ParserMatchClass = UImmAsmOperand<5>;
let DecoderMethod = "decodeUImmOperand<5>";
let OperandNamespace = "RISCVOp";
}
+def uimm8 : Operand<XLenVT> {
+ let ParserMatchClass = UImmAsmOperand<8>;
+ let DecoderMethod = "decodeUImmOperand<8>";
+ let OperandType = "OPERAND_UIMM8";
+ let OperandNamespace = "RISCVOp";
+}
+
def simm12 : Operand<XLenVT>, ImmLeaf<XLenVT, [{return isInt<12>(Imm);}]> {
let ParserMatchClass = SImmAsmOperand<12>;
let EncoderMethod = "getImmOpValue";
let OperandType = "OPERAND_PCREL";
}
+def InsnCDirectiveOpcode : AsmOperandClass {
+ let Name = "InsnCDirectiveOpcode";
+ let ParserMethod = "parseInsnCDirectiveOpcode";
+ let RenderMethod = "addImmOperands";
+ let PredicateMethod = "isImm";
+}
+
+def uimm2_opcode : Operand<XLenVT> {
+ let ParserMatchClass = InsnCDirectiveOpcode;
+ let DecoderMethod = "decodeUImmOperand<2>";
+ let OperandType = "OPERAND_UIMM2";
+ let OperandNamespace = "RISCVOp";
+}
+
//===----------------------------------------------------------------------===//
// Instruction Class Templates
//===----------------------------------------------------------------------===//
}
} // EmitPriority = 0
+//===----------------------------------------------------------------------===//
+// .insn directive instructions
+//===----------------------------------------------------------------------===//
+
+def AnyRegCOperand : AsmOperandClass {
+ let Name = "AnyRegCOperand";
+ let RenderMethod = "addRegOperands";
+ let PredicateMethod = "isAnyRegC";
+}
+
+def AnyRegC : Operand<XLenVT> {
+ 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.
//===----------------------------------------------------------------------===//
--- /dev/null
+# 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
+
--- /dev/null
+# 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 <target>
+.insn cb 1, 6, a0, target
+
+# CHECK-ASM: .insn cj 1, 5, target
+# CHECK-ASM: encoding: [0bAAAAAA01,0b101AAAAA]
+# CHECK-OBJ: c.j 0x0 <target>
+.insn cj 1, 5, target