652 changes: 652 additions & 0 deletions llvm/lib/Target/CSKY/AsmParser/CSKYAsmParser.cpp

Large diffs are not rendered by default.

8 changes: 6 additions & 2 deletions llvm/lib/Target/CSKY/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ add_llvm_component_group(CSKY)

set(LLVM_TARGET_DEFINITIONS CSKY.td)

tablegen(LLVM CSKYGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM CSKYGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM CSKYGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM CSKYGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM CSKYGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM CSKYGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM CSKYGenSubtargetInfo.inc -gen-subtarget)

add_public_tablegen_target(CSKYCommonTableGen)

Expand All @@ -22,5 +25,6 @@ add_llvm_target(CSKYCodeGen
CSKY
)

add_subdirectory(TargetInfo)
add_subdirectory(AsmParser)
add_subdirectory(MCTargetDesc)
add_subdirectory(TargetInfo)
15 changes: 14 additions & 1 deletion llvm/lib/Target/CSKY/CSKY.td
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,27 @@ include "CSKYInstrInfo.td"
// CSKY processors supported.
//===----------------------------------------------------------------------===//

def : ProcessorModel<"generic-csky", NoSchedModel, []>;
def : ProcessorModel<"generic", NoSchedModel, []>;

//===----------------------------------------------------------------------===//
// Define the CSKY target.
//===----------------------------------------------------------------------===//

def CSKYInstrInfo : InstrInfo;


def CSKYAsmParser : AsmParser {
let ShouldEmitMatchRegisterAltName = 1;
let AllowDuplicateRegisterNames = 1;
}

def CSKYAsmWriter : AsmWriter {
int PassSubtarget = 1;
}

def CSKY : Target {
let InstructionSet = CSKYInstrInfo;
let AssemblyParsers = [CSKYAsmParser];
let AssemblyWriters = [CSKYAsmWriter];
let AllowRegisterRenaming = 1;
}
80 changes: 42 additions & 38 deletions llvm/lib/Target/CSKY/CSKYInstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ class J<bits<6> opcode, dag outs, dag ins, string op, list<dag> pattern>
pattern> {
bits<26> offset;
let Inst{25 - 0} = offset;
let isCall = 1;
let Defs = [ R15 ];
}

// 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),
!strconcat(op, "\t$rz, $offset"), pattern> {
class I_18_Z_L<bits<3> sop, string asm, dag outs, dag ins, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x33, outs, ins, asm, pattern> {
bits<5> rz;
bits<18> offset;
let Inst{25 - 21} = rz;
Expand Down Expand Up @@ -100,10 +101,9 @@ class I_16_MOV<bits<5> sop, string op, ImmLeaf ImmType>

// 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;
Expand All @@ -113,22 +113,14 @@ class I_16_Z_L<bits<5> sop, string op, Operand operand, list<dag> pattern>

// Format< OP[6] | SOP[5] | 00000[5] | OFFSET[16] >
// Instructions(5): bt32, bf32, br32, jmpi32, jsri32
class I_16_L<bits<5> sop, dag outs, dag ins, string op, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x3a, outs, ins, !strconcat(op, "\t$imm16"),
pattern> {
class I_16_L<bits<5> sop, dag outs, dag ins, string asm, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x3a, outs, ins, asm, pattern> {
bits<16> imm16;
let Inst{25 - 21} = sop;
let Inst{20 - 16} = 0;
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>
Expand Down Expand Up @@ -167,11 +159,24 @@ class I_16_RET<bits<5> sop, bits<5> pcode, string op, list<dag> pattern>
let isBarrier = 1;
}

// Instructions(1): rte32
class I_16_RET_I<bits<5> sop, bits<5> pcode, string op, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x30, (outs), (ins), op, pattern> {
let Inst{25 - 21} = sop;
let Inst{20 - 16} = pcode;
let Inst{15 - 10} = 0x10;
let Inst{9 - 5} = 1;
let Inst{4 - 0} = 0;
let isTerminator = 1;
let isReturn = 1;
let isBarrier = 1;
}

// 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;
Expand Down Expand Up @@ -211,7 +216,7 @@ class I_12<bits<4> sop, string op, SDNode node, ImmLeaf ImmType>

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;
Expand Down Expand Up @@ -298,13 +303,13 @@ class I_5_YX<bits<6> opcode, dag outs, dag ins, string op, list<dag> pattern,

// 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;
Expand All @@ -313,12 +318,12 @@ class I_5_XZ_U<bits<6> sop, bits<5> lsb, bits<5> msb, dag outs, dag ins,
}

// 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]>
Expand Down Expand Up @@ -401,27 +406,26 @@ class R_YXZ_SP_F1<bits<6> sop, bits<5> pcode, PatFrag opnode, string op,
// 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
Expand Down
236 changes: 231 additions & 5 deletions llvm/lib/Target/CSKY/CSKYInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -10,47 +10,132 @@
//
//===----------------------------------------------------------------------===//

include "CSKYInstrFormats.td"

//===----------------------------------------------------------------------===//
// CSKY specific DAG Nodes.
//===----------------------------------------------------------------------===//

// TODO: Add CSKY specific DAG Nodes.
// Target-dependent nodes.
def CSKY_RET : SDNode<"CSKYISD::RET", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;

//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
//===----------------------------------------------------------------------===//
class ImmAsmOperand<string prefix, int width, string suffix> : AsmOperandClass {
let Name = prefix # "Imm" # width # suffix;
let RenderMethod = "addImmOperands";
let DiagnosticType = !strconcat("Invalid", Name);
}

class SImmAsmOperand<int width, string suffix = "">
: ImmAsmOperand<"S", width, suffix> {
}

class UImmAsmOperand<int width, string suffix = "">
: ImmAsmOperand<"U", width, suffix> {
}

class OImmAsmOperand<int width, string suffix = "">
: ImmAsmOperand<"O", width, suffix> {
}

class oimm<int num> : Operand<i32>,
ImmLeaf<i32, "return isUInt<"#num#">(Imm - 1);"> {
let EncoderMethod = "getOImmOpValue";
let ParserMatchClass = OImmAsmOperand<num>;
}

class uimm<int num, int shift = 0> : Operand<i32>,
ImmLeaf<i32, "return isShiftedUInt<"#num#", "#shift#">(Imm);"> {
let EncoderMethod = "getImmOpValue<"#shift#">";
let ParserMatchClass =
!if(!ne(shift, 0),
UImmAsmOperand<num, "Shift"#shift>,
UImmAsmOperand<num>);
}

class simm<int num, int shift = 0> : Operand<i32>,
ImmLeaf<i32, "return isShiftedInt<"#num#", "#shift#">(Imm);"> {
let EncoderMethod = "getImmOpValue<"#shift#">";
let ParserMatchClass = SImmAsmOperand<num>;
}

def nimm_XFORM : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant(~N->getSExtValue(), SDLoc(N), MVT::i32);
}]>;
class nimm<int num> : Operand<i32>,
ImmLeaf<i32, "return isUInt<"#num#">(~Imm);", nimm_XFORM> {
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 CSKYSymbol : AsmOperandClass {
let Name = "CSKYSymbol";
let RenderMethod = "addImmOperands";
let DiagnosticType = "InvalidCSKYSymbol";
let ParserMethod = "parseCSKYSymbol";
}

def br_symbol : Operand<iPTR> {
let EncoderMethod =
"getBranchSymbolOpValue<CSKY::fixup_csky_pcrel_imm16_scale2>";
let ParserMatchClass = CSKYSymbol;
}

def call_symbol : Operand<iPTR> {
let ParserMatchClass = CSKYSymbol;
let EncoderMethod = "getCallSymbolOpValue";
}

def Constpool : AsmOperandClass {
let Name = "ConstpoolSymbol";
let RenderMethod = "addImmOperands";
let DiagnosticType = "InvalidConstpool";
let ParserMethod = "parseConstpoolSymbol";
}

def constpool_symbol : Operand<iPTR> {
let ParserMatchClass = Constpool;
let EncoderMethod =
"getConstpoolSymbolOpValue<CSKY::fixup_csky_pcrel_uimm16_scale4>";
}

def bare_symbol : Operand<iPTR> {
let ParserMatchClass = CSKYSymbol;
let EncoderMethod = "getBareSymbolOpValue";
}

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.
Expand All @@ -60,10 +145,18 @@ class TriOpFrag<dag res> : PatFrag<(ops node: $LHS, node:$MHS, node:$RHS), res>;
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),
Expand All @@ -74,8 +167,9 @@ def LSRI32 : I_5_XZ<0x12, 0x2, "lsri32",
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>;
Expand Down Expand Up @@ -103,6 +197,138 @@ def DIVS32 : R_YXZ_SP_F1<0x20, 0x2,
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),
"not", [(set GPR:$rz, (not 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">;

//===----------------------------------------------------------------------===//
// Branch and call instructions.
//===----------------------------------------------------------------------===//

let isBranch = 1, isTerminator = 1 in {
let isBarrier = 1, isPredicable = 1 in
def BR32 : I_16_L<0x0, (outs), (ins br_symbol:$imm16), "br32\t$imm16",
[(br bb:$imm16)]>;

def BT32 : I_16_L<0x3, (outs), (ins CARRY:$ca, br_symbol:$imm16),
"bt32\t$imm16", [(brcond CARRY:$ca, bb:$imm16)]>;
def BF32 : I_16_L<0x2, (outs), (ins CARRY:$ca, br_symbol:$imm16),
"bf32\t$imm16", []>;
}


def BEZ32 : I_16_X_L<0x8, "bez32", br_symbol>;
def BNEZ32 : I_16_X_L<0x9, "bnez32", br_symbol>;
def BHZ32 : I_16_X_L<0xA, "bhz32", br_symbol>;
def BLSZ32 : I_16_X_L<0xB, "blsz32", br_symbol>;
def BLZ32 : I_16_X_L<0xC, "blz32", br_symbol>;
def BHSZ32 : I_16_X_L<0xD, "bhsz32", br_symbol>;

let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
def JMP32 : I_16_JX<0x6, "jmp32", [(brind GPR:$rx)]>; // jmp to register
def JMPI32 : I_16_L<0x16, (outs), (ins constpool_symbol:$imm16),
"jmpi32\t$imm16", []>;
}

let isCall = 1, Defs = [ R15 ] in
def JSR32 : I_16_JX<0x7, "jsr32", []>;

let isCall = 1, Defs = [ R15 ] , mayLoad = 1 in
def JSRI32: I_16_L<0x17, (outs),
(ins constpool_symbol:$imm16), "jsri32\t$imm16", []>;


def BSR32 : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>;

def BSR32_BR : J<0x38, (outs), (ins call_symbol:$offset), "bsr32", []>{
let isCodeGenOnly = 1;
let isBranch = 1;
let isTerminator = 1;
let isBarrier = 1;
let isPredicable = 1;
let Defs = [ R15 ];
}

def RTS32 : I_16_RET<0x6, 0xF, "rts32", [(CSKY_RET)]>;


def RTE32 : I_16_RET_I<0, 0, "rte32", []>;

//===----------------------------------------------------------------------===//
// Symbol address instructions.
//===----------------------------------------------------------------------===//

def GRS32 : I_18_Z_L<0x3, "grs32\t$rz, $offset",
(outs GPR:$rz), (ins bare_symbol:$offset), []>;

let mayLoad = 1, mayStore = 0 in {
def LRW32 : I_16_Z_L<0x14, "lrw32", (ins constpool_symbol:$imm16), []>;
let isCodeGenOnly = 1 in
def LRW32_Gen : I_16_Z_L<0x14, "lrw32", (ins bare_symbol:$src1, constpool_symbol:$imm16), []>;
}
4 changes: 3 additions & 1 deletion llvm/lib/Target/CSKY/MCTargetDesc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
add_llvm_component_library(LLVMCSKYDesc
CSKYAsmBackend.cpp
CSKYELFObjectWriter.cpp
CSKYInstPrinter.cpp
CSKYMCAsmInfo.cpp
CSKYMCExpr.cpp
CSKYMCTargetDesc.cpp
CSKYMCCodeEmitter.cpp

LINK_COMPONENTS
MC
CSKYInfo
MC
Support

ADD_TO_COMPONENT
Expand Down
104 changes: 102 additions & 2 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "CSKYAsmBackend.h"
#include "MCTargetDesc/CSKYMCTargetDesc.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
Expand All @@ -24,14 +25,113 @@ CSKYAsmBackend::createObjectTargetWriter() const {
return createCSKYELFObjectWriter();
}

unsigned int CSKYAsmBackend::getNumFixupKinds() const { return 1; }
const MCFixupKindInfo &
CSKYAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {

static llvm::DenseMap<unsigned, MCFixupKindInfo> Infos = {
{CSKY::Fixups::fixup_csky_addr32, {"fixup_csky_addr32", 0, 32, 0}},
{CSKY::Fixups::fixup_csky_pcrel_imm16_scale2,
{"fixup_csky_pcrel_imm16_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
{CSKY::Fixups::fixup_csky_pcrel_uimm16_scale4,
{"fixup_csky_pcrel_uimm16_scale4", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
{CSKY::Fixups::fixup_csky_pcrel_imm26_scale2,
{"fixup_csky_pcrel_imm26_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}},
{CSKY::Fixups::fixup_csky_pcrel_imm18_scale2,
{"fixup_csky_pcrel_imm18_scale2", 0, 32, MCFixupKindInfo::FKF_IsPCRel}}};
assert(Infos.size() == CSKY::NumTargetFixupKinds &&
"Not all fixup kinds added to Infos array");

assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
"Invalid kind!");
if (FirstTargetFixupKind <= Kind && Kind < FirstLiteralRelocationKind)
return Infos[Kind];
else if (Kind < FirstTargetFixupKind)
return MCAsmBackend::getFixupKindInfo(Kind);
else
return MCAsmBackend::getFixupKindInfo(FK_NONE);
}

static uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
MCContext &Ctx) {
switch (Fixup.getTargetKind()) {
default:
llvm_unreachable("Unknown fixup kind!");
case FK_Data_1:
case FK_Data_2:
case FK_Data_4:
case FK_Data_8:
return Value;
case CSKY::fixup_csky_addr32:
return Value & 0xffffffff;
case CSKY::fixup_csky_pcrel_imm16_scale2:
if (!isIntN(17, Value))
Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
if (Value & 0x1)
Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");

return (Value >> 1) & 0xffff;
case CSKY::fixup_csky_pcrel_uimm16_scale4:
if (!isUIntN(18, Value))
Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
if (Value & 0x3)
Ctx.reportError(Fixup.getLoc(), "fixup value must be 4-byte aligned.");

return (Value >> 2) & 0xffff;
case CSKY::fixup_csky_pcrel_imm26_scale2:
if (!isIntN(27, Value))
Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
if (Value & 0x1)
Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");

return (Value >> 1) & 0x3ffffff;
case CSKY::fixup_csky_pcrel_imm18_scale2:
if (!isIntN(19, Value))
Ctx.reportError(Fixup.getLoc(), "out of range pc-relative fixup value.");
if (Value & 0x1)
Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned.");

return (Value >> 1) & 0x3ffff;
}
}

void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value,
bool IsResolved,
const MCSubtargetInfo *STI) const {
return;
MCFixupKind Kind = Fixup.getKind();
if (Kind >= FirstLiteralRelocationKind)
return;
MCContext &Ctx = Asm.getContext();
MCFixupKindInfo Info = getFixupKindInfo(Kind);
if (!Value)
return; // Doesn't change encoding.
// Apply any target-specific value adjustments.
Value = adjustFixupValue(Fixup, Value, Ctx);

// Shift the value into position.
Value <<= Info.TargetOffset;

unsigned Offset = Fixup.getOffset();
unsigned NumBytes = alignTo(Info.TargetSize + Info.TargetOffset, 8) / 8;

assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!");

// For each byte of the fragment that the fixup touches, mask in the
// bits from the fixup value.
bool IsLittleEndian = (Endian == support::little);

if (IsLittleEndian && (NumBytes == 4)) {
Data[Offset + 0] |= uint8_t((Value >> 16) & 0xff);
Data[Offset + 1] |= uint8_t((Value >> 24) & 0xff);
Data[Offset + 2] |= uint8_t(Value & 0xff);
Data[Offset + 3] |= uint8_t((Value >> 8) & 0xff);
} else {
for (unsigned I = 0; I != NumBytes; I++) {
unsigned Idx = IsLittleEndian ? I : (NumBytes - 1 - I);
Data[Offset + Idx] |= uint8_t((Value >> (I * 8)) & 0xff);
}
}
}

bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
Expand Down
12 changes: 11 additions & 1 deletion llvm/lib/Target/CSKY/MCTargetDesc/CSKYAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYASMBACKEND_H
#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYASMBACKEND_H

#include "MCTargetDesc/CSKYFixupKinds.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCTargetOptions.h"

Expand All @@ -20,17 +21,26 @@ class CSKYAsmBackend : public MCAsmBackend {
CSKYAsmBackend(const MCSubtargetInfo &STI, const MCTargetOptions &OP)
: MCAsmBackend(support::little) {}

unsigned int getNumFixupKinds() const override;
unsigned int getNumFixupKinds() const override {
return CSKY::NumTargetFixupKinds;
}

void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const override;

const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;

bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override;

void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override;

bool writeNopData(raw_ostream &OS, uint64_t Count) const override;

std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override;
};
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYFixupKinds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===-- CSKYFixupKinds.h - CSKY Specific Fixup Entries ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYFIXUPKINDS_H
#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYFIXUPKINDS_H

#include "llvm/MC/MCFixup.h"

namespace llvm {
namespace CSKY {
enum Fixups {
fixup_csky_addr32 = FirstTargetFixupKind,

fixup_csky_pcrel_imm16_scale2,

fixup_csky_pcrel_uimm16_scale4,

fixup_csky_pcrel_imm26_scale2,

fixup_csky_pcrel_imm18_scale2,

// Marker
fixup_csky_invalid,
NumTargetFixupKinds = fixup_csky_invalid - FirstTargetFixupKind
};
} // end namespace CSKY
} // end namespace llvm

#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYFIXUPKINDS_H
101 changes: 101 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
//===-- CSKYInstPrinter.cpp - Convert CSKY MCInst to asm syntax ---------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class prints an CSKY MCInst to a .s file.
//
//===----------------------------------------------------------------------===//

#include "CSKYInstPrinter.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"

using namespace llvm;

#define DEBUG_TYPE "csky-asm-printer"

// Include the auto-generated portion of the assembly writer.
#define PRINT_ALIAS_INSTR
#include "CSKYGenAsmWriter.inc"

static cl::opt<bool>
NoAliases("csky-no-aliases",
cl::desc("Disable the emission of assembler pseudo instructions"),
cl::init(false), cl::Hidden);

static cl::opt<bool>
ArchRegNames("csky-arch-reg-names",
cl::desc("Print architectural register names rather than the "
"ABI names (such as r14 instead of sp)"),
cl::init(false), cl::Hidden);

// The command-line flags above are used by llvm-mc and llc. They can be used by
// `llvm-objdump`, but we override their values here to handle options passed to
// `llvm-objdump` with `-M` (which matches GNU objdump). There did not seem to
// be an easier way to allow these options in all these tools, without doing it
// this way.
bool CSKYInstPrinter::applyTargetSpecificCLOption(StringRef Opt) {
if (Opt == "no-aliases") {
NoAliases = true;
return true;
}
if (Opt == "numeric") {
ArchRegNames = true;
return true;
}

return false;
}

void CSKYInstPrinter::printInst(const MCInst *MI, uint64_t Address,
StringRef Annot, const MCSubtargetInfo &STI,
raw_ostream &O) {
const MCInst *NewMI = MI;

if (NoAliases || !printAliasInstr(NewMI, Address, STI, O))
printInstruction(NewMI, Address, STI, O);
printAnnotation(O, Annot);
}

void CSKYInstPrinter::printRegName(raw_ostream &O, unsigned RegNo) const {
O << getRegisterName(RegNo);
}

void CSKYInstPrinter::printOperand(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O,
const char *Modifier) {
assert((Modifier == 0 || Modifier[0] == 0) && "No modifiers supported");
const MCOperand &MO = MI->getOperand(OpNo);

if (MO.isReg()) {
if (MO.getReg() == CSKY::C)
O << "";
else
printRegName(O, MO.getReg());
return;
}

if (MO.isImm()) {
O << formatImm(MO.getImm());
return;
}

assert(MO.isExpr() && "Unknown operand kind in printOperand");
MO.getExpr()->print(O, &MAI);
}

const char *CSKYInstPrinter::getRegisterName(unsigned RegNo) {
return getRegisterName(RegNo, ArchRegNames ? CSKY::NoRegAltName
: CSKY::ABIRegAltName);
}
52 changes: 52 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYInstPrinter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//===-- CSKYInstPrinter.h - Convert CSKY MCInst to asm syntax ---*- C++ -*----//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This class prints a CSKY MCInst to a .s file.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H
#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H

#include "MCTargetDesc/CSKYMCTargetDesc.h"
#include "llvm/MC/MCInstPrinter.h"

namespace llvm {

class CSKYInstPrinter : public MCInstPrinter {
public:
CSKYInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
const MCRegisterInfo &MRI)
: MCInstPrinter(MAI, MII, MRI) {}

bool applyTargetSpecificCLOption(StringRef Opt) override;

void printInst(const MCInst *MI, uint64_t Address, StringRef Annot,
const MCSubtargetInfo &STI, raw_ostream &O) override;
void printRegName(raw_ostream &O, unsigned RegNo) const override;

void printOperand(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &O, const char *Modifier = nullptr);

// Autogenerated by tblgen.
std::pair<const char *, uint64_t> getMnemonic(const MCInst *MI) override;
void printInstruction(const MCInst *MI, uint64_t Address,
const MCSubtargetInfo &STI, raw_ostream &O);
bool printAliasInstr(const MCInst *MI, uint64_t Address,
const MCSubtargetInfo &STI, raw_ostream &O);
void printCustomAliasOperand(const MCInst *MI, uint64_t Address,
unsigned OpIdx, unsigned PrintMethodIdx,
const MCSubtargetInfo &STI, raw_ostream &O);

static const char *getRegisterName(unsigned RegNo);
static const char *getRegisterName(unsigned RegNo, unsigned AltIdx);
};

} // namespace llvm

#endif // LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYINSTPRINTER_H
11 changes: 11 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,17 @@ CSKYMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
return 0;
}

MCFixupKind CSKYMCCodeEmitter::getTargetFixup(const MCExpr *Expr) const {
const CSKYMCExpr *CSKYExpr = cast<CSKYMCExpr>(Expr);

switch (CSKYExpr->getKind()) {
default:
llvm_unreachable("Unhandled fixup kind!");
case CSKYMCExpr::VK_CSKY_ADDR:
return MCFixupKind(CSKY::fixup_csky_addr32);
}
}

MCCodeEmitter *llvm::createCSKYMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI,
MCContext &Ctx) {
Expand Down
74 changes: 74 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCCodeEmitter.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H
#define LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H

#include "CSKYMCExpr.h"
#include "MCTargetDesc/CSKYFixupKinds.h"
#include "llvm/MC/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h"

Expand Down Expand Up @@ -54,6 +56,78 @@ class CSKYMCCodeEmitter : public MCCodeEmitter {
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();
}

MCFixupKind getTargetFixup(const MCExpr *Expr) const;

template <llvm::CSKY::Fixups FIXUP>
unsigned getBranchSymbolOpValue(const MCInst &MI, unsigned Idx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(Idx);

if (MO.isImm())
return MO.getImm() >> 1;

assert(MO.isExpr() && "Unexpected MO type.");

MCFixupKind Kind = MCFixupKind(FIXUP);
if (MO.getExpr()->getKind() == MCExpr::Target)
Kind = getTargetFixup(MO.getExpr());

Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));
return 0;
}

template <llvm::CSKY::Fixups FIXUP>
unsigned getConstpoolSymbolOpValue(const MCInst &MI, unsigned Idx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(Idx);
assert(MO.isExpr() && "Unexpected MO type.");

MCFixupKind Kind = MCFixupKind(FIXUP);
if (MO.getExpr()->getKind() == MCExpr::Target)
Kind = getTargetFixup(MO.getExpr());

Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));
return 0;
}

unsigned getCallSymbolOpValue(const MCInst &MI, unsigned Idx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(Idx);
assert(MO.isExpr() && "Unexpected MO type.");

MCFixupKind Kind = MCFixupKind(CSKY::fixup_csky_pcrel_imm26_scale2);
if (MO.getExpr()->getKind() == MCExpr::Target)
Kind = getTargetFixup(MO.getExpr());

Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));
return 0;
}

unsigned getBareSymbolOpValue(const MCInst &MI, unsigned Idx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
const MCOperand &MO = MI.getOperand(Idx);
assert(MO.isExpr() && "Unexpected MO type.");

MCFixupKind Kind = MCFixupKind(CSKY::fixup_csky_pcrel_imm18_scale2);
if (MO.getExpr()->getKind() == MCExpr::Target)
Kind = getTargetFixup(MO.getExpr());

Fixups.push_back(MCFixup::create(0, MO.getExpr(), Kind, MI.getLoc()));
return 0;
}
};

} // namespace llvm
Expand Down
122 changes: 122 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//===-- CSKYMCExpr.cpp - CSKY specific MC expression classes -*- C++ -*----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "CSKYMCExpr.h"
#include "CSKYFixupKinds.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbolELF.h"

using namespace llvm;

#define DEBUG_TYPE "csky-mc-expr"

const CSKYMCExpr *CSKYMCExpr::create(const MCExpr *Expr, VariantKind Kind,
MCContext &Ctx) {
return new (Ctx) CSKYMCExpr(Kind, Expr);
}

StringRef CSKYMCExpr::getVariantKindName(VariantKind Kind) {
switch (Kind) {
default:
llvm_unreachable("Invalid ELF symbol kind");
case VK_CSKY_ADDR:
return "";
case VK_CSKY_PCREL:
return "";
case VK_CSKY_GOT:
return "@GOT";
case VK_CSKY_GOTPC:
return "@GOTPC";
case VK_CSKY_GOTOFF:
return "@GOTOFF";
case VK_CSKY_PLT:
return "@PLT";
case VK_CSKY_TPOFF:
return "@TPOFF";
case VK_CSKY_TLSGD:
return "@TLSGD";
}
}

void CSKYMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
Streamer.visitUsedExpr(*getSubExpr());
}

void CSKYMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
Expr->print(OS, MAI);
OS << getVariantKindName(getKind());
}

static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
switch (Expr->getKind()) {
case MCExpr::Target:
llvm_unreachable("Can't handle nested target expression");
break;
case MCExpr::Constant:
break;

case MCExpr::Binary: {
const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
break;
}

case MCExpr::SymbolRef: {
// We're known to be under a TLS fixup, so any symbol should be
// modified. There should be only one.
const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
break;
}

case MCExpr::Unary:
fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
break;
}
}

void CSKYMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
switch (getKind()) {
default:
return;
case VK_CSKY_TPOFF:
case VK_CSKY_TLSGD:
break;
}

fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
}

bool CSKYMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
const MCAsmLayout *Layout,
const MCFixup *Fixup) const {
if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
return false;

// Some custom fixup types are not valid with symbol difference expressions
if (Res.getSymA() && Res.getSymB()) {
switch (getKind()) {
default:
return true;

case VK_CSKY_ADDR:
case VK_CSKY_PCREL:
case VK_CSKY_GOT:
case VK_CSKY_GOTPC:
case VK_CSKY_GOTOFF:
case VK_CSKY_TPOFF:
case VK_CSKY_TLSGD:
return false;
}
}

return true;
}
69 changes: 69 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCExpr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//===-- CSKYMCExpr.h - CSKY specific MC expression classes -*- C++ -*----===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCEXPR_H
#define LLVM_LIB_TARGET_LANAI_MCTARGETDESC_LANAIMCEXPR_H

#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCValue.h"

namespace llvm {

class CSKYMCExpr : public MCTargetExpr {
public:
enum VariantKind {
VK_CSKY_None,
VK_CSKY_ADDR,
VK_CSKY_PCREL,
VK_CSKY_GOT,
VK_CSKY_GOTPC,
VK_CSKY_GOTOFF,
VK_CSKY_PLT,
VK_CSKY_TPOFF,
VK_CSKY_TLSGD,
VK_CSKY_Invalid
};

private:
const VariantKind Kind;
const MCExpr *Expr;

explicit CSKYMCExpr(VariantKind Kind, const MCExpr *Expr)
: Kind(Kind), Expr(Expr) {}

public:
static const CSKYMCExpr *create(const MCExpr *Expr, VariantKind Kind,
MCContext &Ctx);

// Returns the kind of this expression.
VariantKind getKind() const { return Kind; }

// Returns the child of this expression.
const MCExpr *getSubExpr() const { return Expr; }

void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;

bool evaluateAsRelocatableImpl(MCValue &Res, const MCAsmLayout *Layout,
const MCFixup *Fixup) const override;
void visitUsedExpr(MCStreamer &Streamer) const override;

MCFragment *findAssociatedFragment() const override {
return getSubExpr()->findAssociatedFragment();
}

void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override;

static bool classof(const MCExpr *E) {
return E->getKind() == MCExpr::Target;
}

static StringRef getVariantKindName(VariantKind Kind);
};
} // end namespace llvm

#endif
23 changes: 23 additions & 0 deletions llvm/lib/Target/CSKY/MCTargetDesc/CSKYMCTargetDesc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "CSKYMCTargetDesc.h"
#include "CSKYAsmBackend.h"
#include "CSKYInstPrinter.h"
#include "CSKYMCAsmInfo.h"
#include "CSKYMCCodeEmitter.h"
#include "TargetInfo/CSKYTargetInfo.h"
Expand All @@ -26,6 +27,9 @@
#define GET_REGINFO_MC_DESC
#include "CSKYGenRegisterInfo.inc"

#define GET_SUBTARGETINFO_MC_DESC
#include "CSKYGenSubtargetInfo.inc"

using namespace llvm;

static MCAsmInfo *createCSKYMCAsmInfo(const MCRegisterInfo &MRI,
Expand All @@ -46,17 +50,36 @@ static MCInstrInfo *createCSKYMCInstrInfo() {
return Info;
}

static MCInstPrinter *createCSKYMCInstPrinter(const Triple &T,
unsigned SyntaxVariant,
const MCAsmInfo &MAI,
const MCInstrInfo &MII,
const MCRegisterInfo &MRI) {
return new CSKYInstPrinter(MAI, MII, MRI);
}

static MCRegisterInfo *createCSKYMCRegisterInfo(const Triple &TT) {
MCRegisterInfo *Info = new MCRegisterInfo();
InitCSKYMCRegisterInfo(Info, CSKY::R15);
return Info;
}

static MCSubtargetInfo *createCSKYMCSubtargetInfo(const Triple &TT,
StringRef CPU, StringRef FS) {
std::string CPUName = std::string(CPU);
if (CPUName.empty())
CPUName = "generic";
return createCSKYMCSubtargetInfoImpl(TT, CPUName, /*TuneCPU=*/CPUName, FS);
}

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeCSKYTargetMC() {
auto &CSKYTarget = getTheCSKYTarget();
TargetRegistry::RegisterMCAsmBackend(CSKYTarget, createCSKYAsmBackend);
TargetRegistry::RegisterMCAsmInfo(CSKYTarget, createCSKYMCAsmInfo);
TargetRegistry::RegisterMCInstrInfo(CSKYTarget, createCSKYMCInstrInfo);
TargetRegistry::RegisterMCRegInfo(CSKYTarget, createCSKYMCRegisterInfo);
TargetRegistry::RegisterMCCodeEmitter(CSKYTarget, createCSKYMCCodeEmitter);
TargetRegistry::RegisterMCInstPrinter(CSKYTarget, createCSKYMCInstPrinter);
TargetRegistry::RegisterMCSubtargetInfo(CSKYTarget,
createCSKYMCSubtargetInfo);
}
412 changes: 412 additions & 0 deletions llvm/test/MC/CSKY/basic.s

Large diffs are not rendered by default.

80 changes: 80 additions & 0 deletions llvm/test/MC/CSKY/csky-error.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# RUN: not llvm-mc -triple=csky %s -filetype=obj -o %t.o 2>&1 | FileCheck %s

# Out of PC range

# br/bt/bf

.L.test1:
.space 0x10001
br32 .L.test1 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned

br32 .L.test2 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned
.space 0x10001
.L.test2:

.L.test3:
.space 0xFFFF
br32 .L.test3 # CHECK: :[[@LINE]]:1: error: fixup value must be 2-byte aligned

.L.test4:
.space 0x10002
br32 .L.test4 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value

# bsr
.L.test5:
.space 0x4000001
bsr32 .L.test5 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned

bsr32 .L.test6 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned
.space 0x4000001
.L.test6:

.L.test7:
.space 0x3FFFFFF
bsr32 .L.test7 # CHECK: :[[@LINE]]:1: error: fixup value must be 2-byte aligned

.L.test8:
.space 0x4000002
bsr32 .L.test8 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value

# grs
.L.test9:
.space 0x40001
grs32 a0, .L.test9 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned

grs32 a0, .L.test10 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 2-byte aligned
.space 0x40001
.L.test10:

.L.test11:
.space 0x3FFFF
grs32 a0, .L.test11 # CHECK: :[[@LINE]]:1: error: fixup value must be 2-byte aligned

.L.test12:
.space 0x40002
grs32 a0, .L.test12 # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value


# TODO: Fixup
lrw32 a0, [.L.test15] # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 4-byte aligned
.space 0x40001
.L.test15:

# TODO: Fixup
jsri32 [.L.test16] # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 4-byte aligned
.space 0x40001
.L.test16:

# TODO: Fixup
jmpi32 [.L.test17] # CHECK: :[[@LINE]]:1: error: out of range pc-relative fixup value
# CHECK: :[[@LINE-1]]:1: error: fixup value must be 4-byte aligned
.space 0x40001
.L.test17:
2 changes: 2 additions & 0 deletions llvm/test/MC/CSKY/lit.local.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
if not 'CSKY' in config.root.targets:
config.unsupported = True