1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00

[CSKY 6/n] Add support branch and symbol series instruction

This patch adds basic CSKY branch instructions and symbol address series instructions.
Those two kinds of instruction have relationship between each other, and it involves much work about Fixups.

For now, basic instructions are enabled except for disassembler support.
We would support to generate basic codegen asm firstly and delay disassembler work later.

Differential Revision: https://reviews.llvm.org/D95029
This commit is contained in:
Zi Xuan Wu 2021-04-20 14:42:26 +08:00
parent 2b6d3d4a3f
commit ca9ceef593
13 changed files with 817 additions and 11 deletions

View File

@ -7,6 +7,7 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "MCTargetDesc/CSKYMCExpr.h"
#include "MCTargetDesc/CSKYMCTargetDesc.h" #include "MCTargetDesc/CSKYMCTargetDesc.h"
#include "TargetInfo/CSKYTargetInfo.h" #include "TargetInfo/CSKYTargetInfo.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
@ -58,6 +59,8 @@ class CSKYAsmParser : public MCTargetAsmParser {
OperandMatchResultTy parseImmediate(OperandVector &Operands); OperandMatchResultTy parseImmediate(OperandVector &Operands);
OperandMatchResultTy parseRegister(OperandVector &Operands); OperandMatchResultTy parseRegister(OperandVector &Operands);
OperandMatchResultTy parseBaseRegImm(OperandVector &Operands); OperandMatchResultTy parseBaseRegImm(OperandVector &Operands);
OperandMatchResultTy parseCSKYSymbol(OperandVector &Operands);
OperandMatchResultTy parseConstpoolSymbol(OperandVector &Operands);
bool parseOperand(OperandVector &Operands, StringRef Mnemonic); bool parseOperand(OperandVector &Operands, StringRef Mnemonic);
@ -171,6 +174,20 @@ public:
bool isUImm12Shift1() { return isUImm<12, 1>(); } bool isUImm12Shift1() { return isUImm<12, 1>(); }
bool isUImm12Shift2() { return isUImm<12, 2>(); } bool isUImm12Shift2() { return isUImm<12, 2>(); }
bool isSImm16Shift1() { return isSImm<16, 1>(); }
bool isCSKYSymbol() const {
int64_t Imm;
// Must be of 'immediate' type but not a constant.
return isImm() && !evaluateConstantImm(getImm(), Imm);
}
bool isConstpoolSymbol() const {
int64_t Imm;
// Must be of 'immediate' type but not a constant.
return isImm() && !evaluateConstantImm(getImm(), Imm);
}
/// Gets location of the first token of this operand. /// Gets location of the first token of this operand.
SMLoc getStartLoc() const override { return StartLoc; } SMLoc getStartLoc() const override { return StartLoc; }
/// Gets location of the last token of this operand. /// Gets location of the last token of this operand.
@ -350,6 +367,14 @@ bool CSKYAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
"immediate must be a multiple of 4 bytes in the range"); "immediate must be a multiple of 4 bytes in the range");
case Match_InvalidUImm16: case Match_InvalidUImm16:
return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1); return generateImmOutOfRangeError(Operands, ErrorInfo, 0, (1 << 16) - 1);
case Match_InvalidCSKYSymbol: {
SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be a symbol name");
}
case Match_InvalidConstpool: {
SMLoc ErrorLoc = ((CSKYOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be a constpool symbol name");
}
} }
llvm_unreachable("Unknown match type detected!"); llvm_unreachable("Unknown match type detected!");
@ -482,6 +507,15 @@ OperandMatchResultTy CSKYAsmParser::parseImmediate(OperandVector &Operands) {
/// information, adding to Operands. If operand was parsed, returns false, else /// information, adding to Operands. If operand was parsed, returns false, else
/// true. /// true.
bool CSKYAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { bool CSKYAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
// Check if the current operand has a custom associated parser, if so, try to
// custom parse the operand, or fallback to the general approach.
OperandMatchResultTy Result =
MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/true);
if (Result == MatchOperand_Success)
return false;
if (Result == MatchOperand_ParseFail)
return true;
// Attempt to parse token as register // Attempt to parse token as register
if (parseRegister(Operands) == MatchOperand_Success) if (parseRegister(Operands) == MatchOperand_Success)
return false; return false;
@ -500,6 +534,68 @@ bool CSKYAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
return true; return true;
} }
OperandMatchResultTy CSKYAsmParser::parseCSKYSymbol(OperandVector &Operands) {
SMLoc S = getLoc();
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
if (getLexer().getKind() != AsmToken::Identifier)
return MatchOperand_NoMatch;
StringRef Identifier;
if (getParser().parseIdentifier(Identifier))
return MatchOperand_ParseFail;
CSKYMCExpr::VariantKind Kind = CSKYMCExpr::VK_CSKY_None;
if (Identifier.consume_back("@GOT"))
Kind = CSKYMCExpr::VK_CSKY_GOT;
else if (Identifier.consume_back("@GOTOFF"))
Kind = CSKYMCExpr::VK_CSKY_GOTOFF;
else if (Identifier.consume_back("@PLT"))
Kind = CSKYMCExpr::VK_CSKY_PLT;
else if (Identifier.consume_back("@GOTPC"))
Kind = CSKYMCExpr::VK_CSKY_GOTPC;
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
const MCExpr *Res =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
if (Kind != CSKYMCExpr::VK_CSKY_None)
Res = CSKYMCExpr::create(Res, Kind, getContext());
Operands.push_back(CSKYOperand::createImm(Res, S, E));
return MatchOperand_Success;
}
OperandMatchResultTy
CSKYAsmParser::parseConstpoolSymbol(OperandVector &Operands) {
SMLoc S = getLoc();
SMLoc E = SMLoc::getFromPointer(S.getPointer() - 1);
if (getLexer().getKind() != AsmToken::LBrac)
return MatchOperand_NoMatch;
getLexer().Lex(); // Eat '['.
if (getLexer().getKind() != AsmToken::Identifier)
return MatchOperand_NoMatch;
StringRef Identifier;
if (getParser().parseIdentifier(Identifier))
return MatchOperand_ParseFail;
if (getLexer().getKind() != AsmToken::RBrac)
return MatchOperand_NoMatch;
getLexer().Lex(); // Eat ']'.
MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
const MCExpr *Res =
MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext());
Operands.push_back(CSKYOperand::createImm(Res, S, E));
return MatchOperand_Success;
}
bool CSKYAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name, bool CSKYAsmParser::ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
SMLoc NameLoc, OperandVector &Operands) { SMLoc NameLoc, OperandVector &Operands) {
// First operand is token for instruction. // First operand is token for instruction.

View File

@ -54,13 +54,14 @@ class J<bits<6> opcode, dag outs, dag ins, string op, list<dag> pattern>
pattern> { pattern> {
bits<26> offset; bits<26> offset;
let Inst{25 - 0} = offset; let Inst{25 - 0} = offset;
let isCall = 1;
let Defs = [ R15 ];
} }
// Format< OP[6] | RZ[5] | SOP[3] | OFFSET[18] > // Format< OP[6] | RZ[5] | SOP[3] | OFFSET[18] >
// Instructions(7): grs, lrs32.b, lrs32.h, lrs32.w, srs32.b, srs32.h, srs32.w // 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, dag outs, dag ins, list<dag> pattern> class I_18_Z_L<bits<3> sop, string asm, dag outs, dag ins, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x33, outs, ins, : CSKY32Inst<AddrModeNone, 0x33, outs, ins, asm, pattern> {
!strconcat(op, "\t$rz, $offset"), pattern> {
bits<5> rz; bits<5> rz;
bits<18> offset; bits<18> offset;
let Inst{25 - 21} = rz; let Inst{25 - 21} = rz;
@ -102,7 +103,7 @@ class I_16_MOV<bits<5> sop, string op, ImmLeaf ImmType>
// Instructions(1): lrw32 // Instructions(1): lrw32
class I_16_Z_L<bits<5> sop, string op, dag ins, list<dag> pattern> class I_16_Z_L<bits<5> sop, string op, dag ins, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x3a, (outs GPR:$rz), ins, : CSKY32Inst<AddrModeNone, 0x3a, (outs GPR:$rz), ins,
!strconcat(op, "\t$rz, [$imm16]"), pattern> { !strconcat(op, "\t$rz, $imm16"), pattern> {
bits<5> rz; bits<5> rz;
bits<16> imm16; bits<16> imm16;
let Inst{25 - 21} = sop; let Inst{25 - 21} = sop;
@ -112,9 +113,8 @@ class I_16_Z_L<bits<5> sop, string op, dag ins, list<dag> pattern>
// Format< OP[6] | SOP[5] | 00000[5] | OFFSET[16] > // Format< OP[6] | SOP[5] | 00000[5] | OFFSET[16] >
// Instructions(5): bt32, bf32, br32, jmpi32, jsri32 // Instructions(5): bt32, bf32, br32, jmpi32, jsri32
class I_16_L<bits<5> sop, dag outs, dag ins, string op, list<dag> pattern> class I_16_L<bits<5> sop, dag outs, dag ins, string asm, list<dag> pattern>
: CSKY32Inst<AddrModeNone, 0x3a, outs, ins, !strconcat(op, "\t$imm16"), : CSKY32Inst<AddrModeNone, 0x3a, outs, ins, asm, pattern> {
pattern> {
bits<16> imm16; bits<16> imm16;
let Inst{25 - 21} = sop; let Inst{25 - 21} = sop;
let Inst{20 - 16} = 0; let Inst{20 - 16} = 0;
@ -159,6 +159,19 @@ class I_16_RET<bits<5> sop, bits<5> pcode, string op, list<dag> pattern>
let isBarrier = 1; 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] > // Format< OP[6] | SOP[5] | RX[5] | IMM16[16] >
// Instructions(3): cmpnei32, cmphsi32, cmplti32 // Instructions(3): cmpnei32, cmphsi32, cmplti32
class I_16_X<bits<5> sop, string op, Operand operand> class I_16_X<bits<5> sop, string op, Operand operand>

View File

@ -15,7 +15,9 @@
// CSKY specific DAG Nodes. // 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. // Operand and SDNode transformation definitions.
@ -81,6 +83,41 @@ def uimm_shift : Operand<i32>, ImmLeaf<i32, "return isUInt<2>(Imm);"> {
let ParserMatchClass = UImmAsmOperand<2>; 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 oimm12 : oimm<12>;
def oimm16 : oimm<16>; def oimm16 : oimm<16>;
@ -229,3 +266,69 @@ def MOVIH32 : I_16_MOV<0x11, "movih32", uimm16_16_xform>;
def MVC32 : R_Z_1<0x1, 0x8, "mvc32">; def MVC32 : R_Z_1<0x1, 0x8, "mvc32">;
def MVCV32 : R_Z_1<0x1, 0x10, "mvcv32">; 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), []>;
}

View File

@ -3,6 +3,7 @@ add_llvm_component_library(LLVMCSKYDesc
CSKYELFObjectWriter.cpp CSKYELFObjectWriter.cpp
CSKYInstPrinter.cpp CSKYInstPrinter.cpp
CSKYMCAsmInfo.cpp CSKYMCAsmInfo.cpp
CSKYMCExpr.cpp
CSKYMCTargetDesc.cpp CSKYMCTargetDesc.cpp
CSKYMCCodeEmitter.cpp CSKYMCCodeEmitter.cpp

View File

@ -8,6 +8,7 @@
#include "CSKYAsmBackend.h" #include "CSKYAsmBackend.h"
#include "MCTargetDesc/CSKYMCTargetDesc.h" #include "MCTargetDesc/CSKYMCTargetDesc.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/MC/MCAsmLayout.h" #include "llvm/MC/MCAsmLayout.h"
#include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCContext.h" #include "llvm/MC/MCContext.h"
@ -24,14 +25,113 @@ CSKYAsmBackend::createObjectTargetWriter() const {
return createCSKYELFObjectWriter(); 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, void CSKYAsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, const MCValue &Target,
MutableArrayRef<char> Data, uint64_t Value, MutableArrayRef<char> Data, uint64_t Value,
bool IsResolved, bool IsResolved,
const MCSubtargetInfo *STI) const { 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, bool CSKYAsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,

View File

@ -9,6 +9,7 @@
#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYASMBACKEND_H #ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYASMBACKEND_H
#define 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/MCAsmBackend.h"
#include "llvm/MC/MCTargetOptions.h" #include "llvm/MC/MCTargetOptions.h"
@ -20,17 +21,26 @@ public:
CSKYAsmBackend(const MCSubtargetInfo &STI, const MCTargetOptions &OP) CSKYAsmBackend(const MCSubtargetInfo &STI, const MCTargetOptions &OP)
: MCAsmBackend(support::little) {} : MCAsmBackend(support::little) {}
unsigned int getNumFixupKinds() const override; unsigned int getNumFixupKinds() const override {
return CSKY::NumTargetFixupKinds;
}
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
const MCValue &Target, MutableArrayRef<char> Data, const MCValue &Target, MutableArrayRef<char> Data,
uint64_t Value, bool IsResolved, uint64_t Value, bool IsResolved,
const MCSubtargetInfo *STI) const override; const MCSubtargetInfo *STI) const override;
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
const MCRelaxableFragment *DF, const MCRelaxableFragment *DF,
const MCAsmLayout &Layout) const override; const MCAsmLayout &Layout) const override;
void relaxInstruction(MCInst &Inst, void relaxInstruction(MCInst &Inst,
const MCSubtargetInfo &STI) const override; const MCSubtargetInfo &STI) const override;
bool writeNopData(raw_ostream &OS, uint64_t Count) const override; bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
std::unique_ptr<MCObjectTargetWriter> std::unique_ptr<MCObjectTargetWriter>
createObjectTargetWriter() const override; createObjectTargetWriter() const override;
}; };

View File

@ -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

View File

@ -62,6 +62,17 @@ CSKYMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO,
return 0; 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, MCCodeEmitter *llvm::createCSKYMCCodeEmitter(const MCInstrInfo &MCII,
const MCRegisterInfo &MRI, const MCRegisterInfo &MRI,
MCContext &Ctx) { MCContext &Ctx) {

View File

@ -13,6 +13,8 @@
#ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H #ifndef LLVM_LIB_TARGET_CSKY_MCTARGETDESC_CSKYMCCODEEMITTER_H
#define 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/MCCodeEmitter.h"
#include "llvm/MC/MCContext.h" #include "llvm/MC/MCContext.h"
@ -62,6 +64,70 @@ public:
assert(MO.isImm() && "Unexpected MO type."); assert(MO.isImm() && "Unexpected MO type.");
return 1 << MO.getImm(); 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 } // namespace llvm

View File

@ -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;
}

View File

@ -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

View File

@ -240,6 +240,102 @@ zext32 a3, l0, 7, 0
# CHECK-ASM: encoding: [0x04,0xc4,0xe3,0x58] # CHECK-ASM: encoding: [0x04,0xc4,0xe3,0x58]
sext32 a3, l0, 7, 0 sext32 a3, l0, 7, 0
# CHECK-ASM: br32 .L.test
# CHECK-ASM: encoding: [A,0xe8'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test, kind: fixup_csky_pcrel_imm16_scale2
.L.test:
br32 .L.test
# CHECK-ASM: bt32 .L.test2
# CHECK-ASM: encoding: [0x60'A',0xe8'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test2, kind: fixup_csky_pcrel_imm16_scale2
.L.test2:
bt32 .L.test2
# CHECK-ASM: bf32 .L.test3
# CHECK-ASM: encoding: [0x40'A',0xe8'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test3, kind: fixup_csky_pcrel_imm16_scale2
.L.test3:
bf32 .L.test3
# CHECK-ASM: bez32 a0, .L.test4
# CHECK-ASM: encoding: [A,0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test4, kind: fixup_csky_pcrel_imm16_scale2
.L.test4:
bez32 a0, .L.test4
# CHECK-ASM: bnez32 a0, .L.test5
# CHECK-ASM: encoding: [0x20'A',0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test5, kind: fixup_csky_pcrel_imm16_scale2
.L.test5:
bnez32 a0, .L.test5
# CHECK-ASM: bhz32 a0, .L.test6
# CHECK-ASM: encoding: [0x40'A',0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test6, kind: fixup_csky_pcrel_imm16_scale2
.L.test6:
bhz32 a0, .L.test6
# CHECK-ASM: blsz32 a0, .L.test7
# CHECK-ASM: encoding: [0x60'A',0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test7, kind: fixup_csky_pcrel_imm16_scale2
.L.test7:
blsz32 a0, .L.test7
# CHECK-ASM: blz32 a0, .L.test8
# CHECK-ASM: encoding: [0x80'A',0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test8, kind: fixup_csky_pcrel_imm16_scale2
.L.test8:
blz32 a0, .L.test8
# CHECK-ASM: bhsz32 a0, .L.test9
# CHECK-ASM: encoding: [0xa0'A',0xe9'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test9, kind: fixup_csky_pcrel_imm16_scale2
.L.test9:
bhsz32 a0, .L.test9
# CHECK-ASM: jmp32 a3
# CHECK-ASM: encoding: [0xc3,0xe8,0x00,0x00]
jmp32 a3
# CHECK-ASM: jmpi32 .L.test10
# CHECK-ASM: encoding: [0xc0'A',0xea'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test10, kind: fixup_csky_pcrel_uimm16_scale4
.L.test10:
jmpi32 [.L.test10]
# CHECK-ASM: bsr32 .L.test11
# CHECK-ASM: encoding: [A,0xe0'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test11, kind: fixup_csky_pcrel_imm26_scale2
.L.test11:
bsr32 .L.test11
# CHECK-ASM: jsr32 a3
# CHECK-ASM: encoding: [0xe3,0xe8,0x00,0x00]
jsr32 a3
# CHECK-ASM: jsri32 .L.test12
# CHECK-ASM: encoding: [0xe0'A',0xea'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test12, kind: fixup_csky_pcrel_uimm16_scale4
.L.test12:
jsri32 [.L.test12]
# CHECK-ASM: rts32
# CHECK-ASM: encoding: [0xcf,0xe8,0x00,0x00]
rts32
# CHECK-ASM: grs32 a0, .L.test13
# CHECK-ASM: encoding: [0x0c'A',0xcc'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test13, kind: fixup_csky_pcrel_imm18_scale2
.L.test13:
grs32 a0, .L.test13
# CHECK-ASM: lrw32 a0, .L.test14
# CHECK-ASM: encoding: [0x80'A',0xea'A',A,A]
# CHECK-ASM: fixup A - offset: 0, value: .L.test14, kind: fixup_csky_pcrel_uimm16_scale4
.L.test14:
lrw32 a0, [.L.test14]
# RUN: not llvm-mc -triple csky --defsym=ERR=1 < %s 2>&1 | FileCheck %s # RUN: not llvm-mc -triple csky --defsym=ERR=1 < %s 2>&1 | FileCheck %s
.ifdef ERR .ifdef ERR
@ -308,4 +404,9 @@ subi32 t2, t3, 0x50, 0x60 # CHECK: :[[@LINE]]:22: error: invalid operand for ins
xori32 a0, a1 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction xori32 a0, a1 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction
xor32 a0, a2 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction xor32 a0, a2 # CHECK: :[[#@LINE]]:1: error: too few operands for instruction
# Need label
br32 0x100 # CHECK: :[[@LINE]]:6: error: operand must be a symbol name
jmpi32 0x100 # CHECK: :[[@LINE]]:8: error: operand must be a constpool symbol name
bsr32 0x100 # CHECK: :[[@LINE]]:7: error: operand must be a symbol name
.endif .endif

80
test/MC/CSKY/csky-error.s Normal file
View File

@ -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: