This patch adds basic CSKY integer instructions except for branch series such as bsr, br.
It mainly includes basic ALU, load & store, compare and data move instructions.
Branch series instructions need handle complex symbol operand as following patch later.
Differential Revision: https://reviews.llvm.org/D94007
OperandMatchResultTy parseImmediate(OperandVector &Operands);
OperandMatchResultTy parseRegister(OperandVector &Operands);
+ OperandMatchResultTy parseBaseRegImm(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
return false;
}
- template <unsigned num> bool isUImm() const {
+ template <unsigned num, unsigned shift = 0> bool isUImm() const {
if (!isImm())
return false;
int64_t Imm;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
- return IsConstantImm && isUInt<num>(Imm);
+ return IsConstantImm && isShiftedUInt<num, shift>(Imm);
}
template <unsigned num> bool isOImm() const {
return IsConstantImm && isUInt<num>(Imm - 1);
}
- template <unsigned num> bool isSImm() const {
+ template <unsigned num, unsigned shift = 0> bool isSImm() const {
if (!isImm())
return false;
int64_t Imm;
bool IsConstantImm = evaluateConstantImm(getImm(), Imm);
- return IsConstantImm && isInt<num>(Imm);
+ return IsConstantImm && isShiftedInt<num, shift>(Imm);
}
+ bool isUImm2() const { return isUImm<2>(); }
bool isUImm5() const { return isUImm<5>(); }
bool isUImm12() const { return isUImm<12>(); }
+ bool isUImm16() const { return isUImm<16>(); }
+
bool isOImm12() const { return isOImm<12>(); }
+ bool isOImm16() const { return isOImm<16>(); }
+
+ bool isUImm12Shift1() { return isUImm<12, 1>(); }
+ bool isUImm12Shift2() { return isUImm<12, 2>(); }
/// Gets location of the first token of this operand.
SMLoc getStartLoc() const override { return StartLoc; }
CSKYMnemonicSpellCheck(((CSKYOperand &)*Operands[0]).getToken(), FBS);
return Error(IDLoc, "unrecognized instruction mnemonic" + Suggestion);
}
+ case Match_InvalidTiedOperand:
case Match_InvalidOperand: {
SMLoc ErrorLoc = IDLoc;
if (ErrorInfo != ~0U) {
break;
case Match_InvalidOImm12:
return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 12));
- case Match_InvalidUImm12:
- return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1);
+ case Match_InvalidOImm16:
+ return generateImmOutOfRangeError(Operands, ErrorInfo, 1, (1 << 16));
+ case Match_InvalidUImm2:
+ return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 2) - 1);
case Match_InvalidUImm5:
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 5) - 1);
+ case Match_InvalidUImm12:
+ return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 12) - 1);
+ case Match_InvalidUImm12Shift1:
+ return generateImmOutOfRangeError(
+ Operands, ErrorInfo, 0, (1 << 12) - 2,
+ "immediate must be a multiple of 2 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);
}
llvm_unreachable("Unknown match type detected!");
}
}
+OperandMatchResultTy CSKYAsmParser::parseBaseRegImm(OperandVector &Operands) {
+ assert(getLexer().is(AsmToken::LParen));
+
+ Operands.push_back(CSKYOperand::createToken("(", getLoc()));
+
+ auto Tok = getParser().Lex(); // Eat '('
+
+ if (parseRegister(Operands) != MatchOperand_Success) {
+ getLexer().UnLex(Tok);
+ Operands.pop_back();
+ return MatchOperand_ParseFail;
+ }
+
+ if (getLexer().isNot(AsmToken::Comma)) {
+ Error(getLoc(), "expected ','");
+ return MatchOperand_ParseFail;
+ }
+
+ getParser().Lex(); // Eat ','
+
+ if (parseRegister(Operands) == MatchOperand_Success) {
+ if (getLexer().isNot(AsmToken::LessLess)) {
+ Error(getLoc(), "expected '<<'");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(CSKYOperand::createToken("<<", getLoc()));
+
+ getParser().Lex(); // Eat '<<'
+
+ if (parseImmediate(Operands) != MatchOperand_Success) {
+ Error(getLoc(), "expected imm");
+ return MatchOperand_ParseFail;
+ }
+
+ } else if (parseImmediate(Operands) != MatchOperand_Success) {
+ Error(getLoc(), "expected imm");
+ return MatchOperand_ParseFail;
+ }
+
+ if (getLexer().isNot(AsmToken::RParen)) {
+ Error(getLoc(), "expected ')'");
+ return MatchOperand_ParseFail;
+ }
+
+ Operands.push_back(CSKYOperand::createToken(")", getLoc()));
+
+ getParser().Lex(); // Eat ')'
+
+ return MatchOperand_Success;
+}
+
OperandMatchResultTy CSKYAsmParser::parseImmediate(OperandVector &Operands) {
switch (getLexer().getKind()) {
default:
if (parseRegister(Operands) == MatchOperand_Success)
return false;
+ // Attempt to parse token as (register, imm)
+ if (getLexer().is(AsmToken::LParen))
+ if (parseBaseRegImm(Operands) == MatchOperand_Success)
+ return false;
+
// Attempt to parse token as a imm.
if (parseImmediate(Operands) == MatchOperand_Success)
return false;
// Format< OP[6] | RZ[5] | SOP[3] | OFFSET[18] >
// Instructions(7): grs, lrs32.b, lrs32.h, lrs32.w, srs32.b, srs32.h, srs32.w
-class I_18_Z_L<bits<3> sop, string op, Operand operand, list<dag> pattern>
- : CSKY32Inst<AddrModeNone, 0x33, (outs GPR:$rz), (ins operand:$offset),
+class I_18_Z_L<bits<3> sop, string op, dag outs, dag ins, list<dag> pattern>
+ : CSKY32Inst<AddrModeNone, 0x33, outs, ins,
!strconcat(op, "\t$rz, $offset"), pattern> {
bits<5> rz;
bits<18> offset;
// Format< OP[6] | SOP[5] | RZ[5] | OFFSET[16] >
// Instructions(1): lrw32
-class I_16_Z_L<bits<5> sop, string op, Operand operand, list<dag> pattern>
- : CSKY32Inst<AddrModeNone, 0x3a,
- (outs GPR:$rz), (ins operand:$imm16),
- !strconcat(op, "\t$rz, [$imm16]"), pattern> {
+class I_16_Z_L<bits<5> sop, string op, dag ins, list<dag> pattern>
+ : CSKY32Inst<AddrModeNone, 0x3a, (outs GPR:$rz), ins,
+ !strconcat(op, "\t$rz, [$imm16]"), pattern> {
bits<5> rz;
bits<16> imm16;
let Inst{25 - 21} = sop;
let Inst{15 - 0} = imm16;
}
-// bt32, bf32, br32, jmpi32
-class I_16_L_B<bits<5> sop, string op, Operand operand, list<dag> pattern>
- : I_16_L<sop, (outs), (ins operand:$imm16, CARRY:$ca), op, pattern> {
- let isBranch = 1;
- let isTerminator = 1;
-}
-
// Format< OP[6] | SOP[5] | RX[5] | 0000000000000000[16] >
// Instructions(2): jmp32, jsr32
class I_16_JX<bits<5> sop, string op, list<dag> pattern>
// Format< OP[6] | SOP[5] | RX[5] | IMM16[16] >
// Instructions(3): cmpnei32, cmphsi32, cmplti32
-class I_16_X<bits<5> sop, string op>
+class I_16_X<bits<5> sop, string op, Operand operand>
: CSKY32Inst<AddrModeNone, 0x3a, (outs CARRY:$ca),
- (ins GPR:$rx, i32imm:$imm16), !strconcat(op, "\t$rx, $imm16"), []> {
+ (ins GPR:$rx, operand:$imm16), !strconcat(op, "\t$rx, $imm16"), []> {
bits<16> imm16;
bits<5> rx;
let Inst{25 - 21} = sop;
class I_LDST<AddrMode am, bits<6> opcode, bits<4> sop, dag outs, dag ins,
string op, list<dag> pattern>
- : CSKY32Inst<am, opcode, outs, ins, !strconcat(op, "\t$rz, ($rx, $imm12)"),
+ : CSKY32Inst<am, opcode, outs, ins, !strconcat(op, "\t$rz, ($rx, ${imm12})"),
pattern> {
bits<5> rx;
bits<5> rz;
// 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_U<bits<6> sop, bits<5> lsb, bits<5> msb, dag outs, dag ins,
- string op, list<dag> pattern>
- : CSKY32Inst<AddrModeNone, 0x31, outs, ins,
- op #"\t$rz, $rx, " #!cast<int>(msb) #", " #!cast<int>(lsb),
+class I_5_XZ_U<bits<6> sop, dag outs, dag ins, string op, list<dag> pattern>
+ : CSKY32Inst<AddrModeNone, 0x31, outs, ins, op #"\t$rz, $rx, $msb, $lsb",
pattern> {
bits<5> rx;
bits<5> rz;
+ bits<5> msb;
+ bits<5> lsb;
let Inst{25 - 21} = lsb; // lsb
let Inst{20 - 16} = rx;
let Inst{15 - 10} = sop;
}
// sextb, sexth
-class I_5_XZ_US<bits<6> sop, bits<5> lsb, bits<5> msb, string op, SDNode opnode,
- ValueType type> : I_5_XZ_U<sop, lsb, msb,
- (outs GPR:$rz), (ins GPR:$rx),op, [(set GPR:$rz, (opnode GPR:$rx, type))]>;
+class I_5_XZ_US<bits<6> sop, string op, SDNode opnode,
+ ValueType type> : I_5_XZ_U<sop, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), op,
+ [(set GPR:$rz, (opnode GPR:$rx, type))]>;
-class I_5_XZ_UZ<bits<6> sop, bits<5> lsb, bits<5> msb, string op, int v>
- : I_5_XZ_U<sop, lsb, msb, (outs GPR:$rz), (ins GPR:$rx), op,
+class I_5_XZ_UZ<bits<6> sop, string op, int v>
+ : I_5_XZ_U<sop, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), op,
[(set GPR:$rz, (and GPR:$rx, (i32 v)))]>;
// Format< OP[6] | RZ[5] | RX[5] | SOP[6] | SIZE[5] | LSB[5]>
// Format< OP[6] | RY[5] | RX[5] | SOP[6] | PCODE[5] | RZ[5] >
// Instructions:(8) ldr32.b, ldr32.h, ldr32.bs, ldr32.hs, ldr32.w,
// str32.b, str32.h, str32.w
-class R_YXZ_LDST<bits<6> opcode, bits<6> sop, bits<5> pcode, int no, dag outs,
+class R_YXZ_LDST<bits<6> opcode, bits<6> sop, dag outs,
dag ins, string op, list<dag> pattern>
: CSKY32Inst<AddrModeNone, opcode, outs, ins,
- op #"\t$rz, ($rx, $ry << " #no #")", pattern> {
+ op # "\t$rz, ($rx, $ry << ${imm})", pattern> {
bits<5> rx;
bits<5> ry;
bits<5> rz;
+ bits<5> imm;
let Inst{25 - 21} = ry; // ry;
let Inst{20 - 16} = rx; // rx;
let Inst{15 - 10} = sop;
- let Inst{9 - 5} = pcode; // pcode;
+ let Inst{9 - 5} = imm; // pcode;
let Inst{4 - 0} = rz;
}
-class I_LDR<bits<6> sop, bits<5> pcode, string op, int no>
- : R_YXZ_LDST<0x34, sop, pcode, no,
- (outs GPR:$rz), (ins GPR:$rx, GPR:$ry), op, []>;
+class I_LDR<bits<6> sop, string op> : R_YXZ_LDST<0x34, sop,
+ (outs GPR:$rz), (ins GPR:$rx, GPR:$ry, uimm_shift:$imm), op, []>;
-class I_STR<bits<6> sop, bits<5> pcode, string op, int no>
- : R_YXZ_LDST<0x35, sop, pcode, no, (outs),
- (ins GPR:$rz, GPR:$rx, GPR:$ry), op, []>;
+class I_STR<bits<6> sop, string op> : R_YXZ_LDST<0x35, sop,
+ (outs), (ins GPR:$rz, GPR:$rx, GPR:$ry, uimm_shift:$imm), op, []>;
// Format< OP[6] | RX[5] | RX[5] | SOP[6] | PCODE[5] | RZ[5] >
// Instructions:(1) not32
//
//===----------------------------------------------------------------------===//
-include "CSKYInstrFormats.td"
//===----------------------------------------------------------------------===//
// CSKY specific DAG Nodes.
class uimm<int num, int shift = 0> : Operand<i32>,
ImmLeaf<i32, "return isShiftedUInt<"#num#", "#shift#">(Imm);"> {
let EncoderMethod = "getImmOpValue<"#shift#">";
- let ParserMatchClass = UImmAsmOperand<num>;
+ let ParserMatchClass =
+ !if(!ne(shift, 0),
+ UImmAsmOperand<num, "Shift"#shift>,
+ UImmAsmOperand<num>);
}
class simm<int num, int shift = 0> : Operand<i32>,
let ParserMatchClass = UImmAsmOperand<num>;
}
+def uimm32_hi16 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((N->getZExtValue() >> 16) & 0xFFFF,
+ SDLoc(N), MVT::i32);
+}]>;
+def uimm16_16_xform : Operand<i32>,
+ ImmLeaf<i32, "return isShiftedUInt<16, 16>(Imm);", uimm32_hi16> {
+ let ParserMatchClass = UImmAsmOperand<16>;
+}
+
+def uimm_shift : Operand<i32>, ImmLeaf<i32, "return isUInt<2>(Imm);"> {
+ let EncoderMethod = "getImmShiftOpValue";
+ let ParserMatchClass = UImmAsmOperand<2>;
+}
+
def oimm12 : oimm<12>;
+def oimm16 : oimm<16>;
def nimm12 : nimm<12>;
def uimm5 : uimm<5>;
def uimm12 : uimm<12>;
+def uimm12_1 : uimm<12, 1>;
+def uimm12_2 : uimm<12, 2>;
+def uimm16 : uimm<16>;
+
+
+//===----------------------------------------------------------------------===//
+// Instruction Formats
+//===----------------------------------------------------------------------===//
+
+include "CSKYInstrFormats.td"
//===----------------------------------------------------------------------===//
// Instruction definitions.
class BinOpFrag<dag res> : PatFrag<(ops node:$LHS, node:$RHS), res>;
class UnOpFrag<dag res> : PatFrag<(ops node:$Src), res>;
+
+
+//===----------------------------------------------------------------------===//
+// Basic ALU instructions.
+//===----------------------------------------------------------------------===//
+
def ADDI32 : I_12<0x0, "addi32", add, oimm12>;
def SUBI32 : I_12<0x1, "subi32", sub, oimm12>;
def ANDI32 : I_12<0x2, "andi32", and, uimm12>;
def ANDNI32 : I_12<0x3, "andni32", and, nimm12>;
+def ORI32 : I_16_ZX<"ori32", uimm16,
+ [(set GPR:$rz, (or GPR:$rx, uimm16:$imm16))]>;
def XORI32 : I_12<0x4, "xori32", xor, uimm12>;
def LSLI32 : I_5_XZ<0x12, 0x1, "lsli32",
(outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5),
def ASRI32 : I_5_XZ<0x12, 0x4, "asri32",
(outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5),
[(set GPR:$rz, (sra GPR:$rx, uimm5:$imm5))]>;
-
-
+def ROTLI32 : I_5_XZ<0x12, 0x8, "rotli32",
+ (outs GPR:$rz), (ins GPR:$rx, uimm5:$imm5),
+ [(set GPR:$rz, (rotl GPR:$rx, uimm5:$imm5))]>;
def ADDU32 : R_YXZ_SP_F1<0x0, 0x1,
BinOpFrag<(add node:$LHS, node:$RHS)>, "addu32", 1>;
BinOpFrag<(sdiv node:$LHS, node:$RHS)>, "divs32">;
def DIVU32 : R_YXZ_SP_F1<0x20, 0x1,
BinOpFrag<(udiv node:$LHS, node:$RHS)>, "divu32">;
+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">;
+def IXD32 : R_YXZ_SP_F1<0x2, 0x4,
+ BinOpFrag<(add node:$LHS, (shl node:$RHS, (i32 3)))>, "ixd32">;
def NOT32 : R_XXZ<0b001001, 0b00100, (outs GPR:$rz), (ins GPR:$rx),
"not32", [(set GPR:$rz, (not GPR:$rx))]>;
+
+def SEXT : I_5_XZ_U<0x16, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "sext32",
+ []>;
+def ZEXT : I_5_XZ_U<0x15, (outs GPR:$rz), (ins GPR:$rx, uimm5:$msb, uimm5:$lsb), "zext32",
+ []>;
+
+
+let isCommutable = 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", []>;
+
+//===----------------------------------------------------------------------===//
+// Load & Store instructions.
+//===----------------------------------------------------------------------===//
+
+def LD32B : I_LD<AddrMode32B, 0x0, "ld32.b", uimm12>;
+def LD32H : I_LD<AddrMode32H, 0x1, "ld32.h", uimm12_1>;
+def LD32W : I_LD<AddrMode32WD, 0x2, "ld32.w", uimm12_2>;
+def LD32BS : I_LD<AddrMode32B, 0x4, "ld32.bs", uimm12>;
+def LD32HS : I_LD<AddrMode32H, 0x5, "ld32.hs", uimm12_1>;
+
+def LDR32B : I_LDR<0x0, "ldr32.b">;
+def LDR32BS : I_LDR<0x4, "ldr32.bs">;
+def LDR32H : I_LDR<0x1, "ldr32.h">;
+def LDR32HS : I_LDR<0x5, "ldr32.hs">;
+def LDR32W : I_LDR<0x2, "ldr32.w">;
+
+def ST32B : I_ST<AddrMode32B, 0x0, "st32.b", uimm12>;
+def ST32H : I_ST<AddrMode32H, 0x1, "st32.h", uimm12_1>;
+def ST32W : I_ST<AddrMode32WD, 0x2, "st32.w", uimm12_2>;
+
+def STR32B : I_STR<0x0, "str32.b">;
+def STR32H : I_STR<0x1, "str32.h">;
+def STR32W : I_STR<0x2, "str32.w">;
+
+//===----------------------------------------------------------------------===//
+// Compare instructions.
+//===----------------------------------------------------------------------===//
+
+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 CMPNE32 : R_YX<0x1, 0x4, "cmpne32">;
+def CMPHS32 : R_YX<0x1, 0x1, "cmphs32">;
+def CMPLT32 : R_YX<0x1, 0x2, "cmplt32">;
+
+//===----------------------------------------------------------------------===//
+// Data move instructions.
+//===----------------------------------------------------------------------===//
+
+def MOVT32 : R_ZX<0x3, 0x2, "movt32", []>;
+def MOVF32 : R_ZX<0x3, 0x1, "movf32", []>;
+def MOV32 : R_XZ<0x12, 0x1, "mov32">;
+def MOVI32 : I_16_MOV<0x10, "movi32", uimm16>;
+def MOVIH32 : I_16_MOV<0x11, "movih32", uimm16_16_xform>;
+
+def MVC32 : R_Z_1<0x1, 0x8, "mvc32">;
+def MVCV32 : R_Z_1<0x1, 0x10, "mvcv32">;
unsigned getOImmOpValue(const MCInst &MI, unsigned Idx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+
+ unsigned getImmShiftOpValue(const MCInst &MI, unsigned Idx,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(Idx);
+ assert(MO.isImm() && "Unexpected MO type.");
+ return 1 << MO.getImm();
+ }
};
} // namespace llvm
# CHECK-ASM: encoding: [0x4e,0xc4,0x80,0x48]
asri32 a0, sp, 2
+# CHECK-ASM: ori32 a0, sp, 2
+# CHECK-ASM: encoding: [0x0e,0xec,0x02,0x00]
+ori32 a0, sp, 2
+
+# CHECK-ASM: rotli32 a0, sp, 2
+# CHECK-ASM: encoding: [0x4e,0xc4,0x00,0x49]
+rotli32 a0, sp, 2
+
+# CHECK-ASM: cmpnei32 a0, 2
+# CHECK-ASM: encoding: [0x40,0xeb,0x02,0x00]
+cmpnei32 a0, 2
+
+# CHECK-ASM: cmphsi32 a0, 2
+# CHECK-ASM: encoding: [0x00,0xeb,0x01,0x00]
+cmphsi32 a0, 2
+
+# CHECK-ASM: cmplti32 a0, 2
+# CHECK-ASM: encoding: [0x20,0xeb,0x01,0x00]
+cmplti32 a0, 2
+
+# CHECK-ASM: movi32 a0, 2
+# CHECK-ASM: encoding: [0x00,0xea,0x02,0x00]
+movi32 a0, 2
+
+# CHECK-ASM: movih32 a0, 2
+# CHECK-ASM: encoding: [0x20,0xea,0x02,0x00]
+movih32 a0, 2
# CHECK-ASM: addu32 a3, l0, l1
# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x00]
# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x80]
divu32 a3, l0, l1
+# CHECK-ASM: ixh32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x23,0x08]
+ixh32 a3, l0, l1
+
+# CHECK-ASM: ixw32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x08]
+ixw32 a3, l0, l1
+
+# CHECK-ASM: ixd32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x83,0x08]
+ixd32 a3, l0, l1
+
+# CHECK-ASM: addc32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x43,0x00]
+addc32 a3, l0, l1
+
+# CHECK-ASM: subc32 a3, l0, l1
+# CHECK-ASM: encoding: [0xa4,0xc4,0x03,0x01]
+subc32 a3, l0, l1
+
+# CHECK-ASM: ld32.b a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xd8,0x02,0x00]
+ld32.b a0, (sp, 2)
+
+# CHECK-ASM: ld32.bs a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xd8,0x02,0x40]
+ld32.bs a0, (sp, 2)
+
+# CHECK-ASM: ld32.h a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xd8,0x01,0x10]
+ld32.h a0, (sp, 2)
+
+# CHECK-ASM: ld32.hs a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xd8,0x01,0x50]
+ld32.hs a0, (sp, 2)
+
+# CHECK-ASM: ld32.w a0, (sp, 4)
+# CHECK-ASM: encoding: [0x0e,0xd8,0x01,0x20]
+ld32.w a0, (sp, 4)
+
+# CHECK-ASM: ldr32.b a0, (sp, l1 << 2)
+# CHECK-ASM: encoding: [0xae,0xd0,0x80,0x00]
+ldr32.b a0, (sp, l1 << 2)
+
+# CHECK-ASM: ldr32.bs a0, (sp, l1 << 2)
+# CHECK-ASM: encoding: [0xae,0xd0,0x80,0x10]
+ldr32.bs a0, (sp, l1 << 2)
+
+# CHECK-ASM: ldr32.h a0, (sp, l1 << 3)
+# CHECK-ASM: encoding: [0xae,0xd0,0x00,0x05]
+ldr32.h a0, (sp, l1 << 3)
+
+# CHECK-ASM: ldr32.hs a0, (sp, l1 << 3)
+# CHECK-ASM: encoding: [0xae,0xd0,0x00,0x15]
+ldr32.hs a0, (sp, l1 << 3)
+
+# CHECK-ASM: ldr32.w a0, (sp, l1 << 3)
+# CHECK-ASM: encoding: [0xae,0xd0,0x00,0x09]
+ldr32.w a0, (sp, l1 << 3)
+
+# CHECK-ASM: st32.b a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xdc,0x02,0x00]
+st32.b a0, (sp, 2)
+
+# CHECK-ASM: st32.h a0, (sp, 2)
+# CHECK-ASM: encoding: [0x0e,0xdc,0x01,0x10]
+st32.h a0, (sp, 2)
+
+# CHECK-ASM: st32.w a0, (sp, 4)
+# CHECK-ASM: encoding: [0x0e,0xdc,0x01,0x20]
+st32.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)
+
+# CHECK-ASM: str32.h a0, (sp, l1 << 3)
+# CHECK-ASM: encoding: [0xae,0xd4,0x00,0x05]
+str32.h a0, (sp, l1 << 3)
+
+# CHECK-ASM: str32.w a0, (sp, l1 << 3)
+# 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: mov32 a3, l0
+# CHECK-ASM: encoding: [0x04,0xc4,0x23,0x48]
+mov32 a3, l0
+
+# CHECK-ASM: movt32 a3, l0
+# CHECK-ASM: encoding: [0x64,0xc4,0x40,0x0c]
+movt32 a3, l0
+
+# CHECK-ASM: movf32 a3, l0
+# CHECK-ASM: encoding: [0x64,0xc4,0x20,0x0c]
+movf32 a3, l0
+
+# CHECK-ASM: mvc32 a3
+# CHECK-ASM: encoding: [0x00,0xc4,0x03,0x05]
+mvc32 a3
+
+# CHECK-ASM: mvcv32 a3
+# CHECK-ASM: encoding: [0x00,0xc4,0x03,0x06]
+mvcv32 a3
+
+# CHECK-ASM: cmpne32 a3, l0
+# CHECK-ASM: encoding: [0x83,0xc4,0x80,0x04]
+cmpne32 a3, l0
+
+# CHECK-ASM: cmphs32 a3, l0
+# CHECK-ASM: encoding: [0x83,0xc4,0x20,0x04]
+cmphs32 a3, l0
+
+# CHECK-ASM: cmplt32 a3, l0
+# CHECK-ASM: encoding: [0x83,0xc4,0x40,0x04]
+cmplt32 a3, l0
+
+# CHECK-ASM: zext32 a3, l0, 7, 0
+# CHECK-ASM: encoding: [0x04,0xc4,0xe3,0x54]
+zext32 a3, l0, 7, 0
+
+# CHECK-ASM: sext32 a3, l0, 7, 0
+# CHECK-ASM: encoding: [0x04,0xc4,0xe3,0x58]
+sext32 a3, l0, 7, 0
# RUN: not llvm-mc -triple csky --defsym=ERR=1 < %s 2>&1 | FileCheck %s
lsli32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
lsri32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
asri32 a0, a0, 32 # CHECK: :[[#@LINE]]:16: error: immediate must be an integer in the range [0, 31]
-
+rotli32 a0, a0, 32 # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 31]
+
+# uimm12(shift0)/uimm12_1/uimm12_2
+ld32.b a0, (a0, -1) # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 4095]
+ld32.h a0, (a0, 4095) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 2 bytes in the range [0, 4094]
+ld32.h a0, (a0, 4093) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 2 bytes in the range [0, 4094]
+ld32.w a0, (a0, 4093) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 4 bytes in the range [0, 4092]
+ld32.w a0, (a0, 2) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 4 bytes in the range [0, 4092]
+ldr32.b a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+ldr32.bs a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:25: error: immediate must be an integer in the range [0, 3]
+ldr32.h a0, (a0, a1 << -1) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+ldr32.hs a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:25: error: immediate must be an integer in the range [0, 3]
+ldr32.w a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+
+st32.b a0, (a0, -1) # CHECK: :[[@LINE]]:17: error: immediate must be an integer in the range [0, 4095]
+st32.h a0, (a0, 4095) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 2 bytes in the range [0, 4094]
+st32.h a0, (a0, 4093) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 2 bytes in the range [0, 4094]
+st32.w a0, (a0, 4093) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 4 bytes in the range [0, 4092]
+st32.w a0, (a0, 2) # CHECK: :[[@LINE]]:17: error: immediate must be a multiple of 4 bytes in the range [0, 4092]
+
+str32.b a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+str32.h a0, (a0, a1 << -1) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+str32.w a0, (a0, a1 << 4) # CHECK: :[[@LINE]]:24: error: immediate must be an integer in the range [0, 3]
+
+# uimm16/oimm16
+ori32 a0, a0, 0x10000 # CHECK: :[[@LINE]]:15: error: immediate must be an integer in the range [0, 65535]
+cmpnei32 a0, 0x10000 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [0, 65535]
+cmphsi32 a0, 0x10001 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [1, 65536]
+cmplti32 a0, 0 # CHECK: :[[@LINE]]:14: error: immediate must be an integer in the range [1, 65536]
+movi32 a0, 0x10000 # CHECK: :[[@LINE]]:12: error: immediate must be an integer in the range [0, 65535]
+movih32 a0, 0x10000 # CHECK: :[[@LINE]]:13: error: immediate must be an integer in the range [0, 65535]
# Invalid mnemonics
subs t0, t2, t1 # CHECK: :[[#@LINE]]:1: error: unrecognized instruction mnemonic
subu32 t0, t2, 1 # CHECK: :[[#@LINE]]:16: error: invalid operand for instruction
# Too many operands
-subu32 t2, t3, 0x50, 0x60 # CHECK: :[[#@LINE]]:22: error: invalid operand for instruction
+subi32 t2, t3, 0x50, 0x60 # CHECK: :[[@LINE]]:22: error: invalid operand for instruction
# Too few operands
xori32 a0, a1 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction