mirror of
https://github.com/RPCS3/llvm.git
synced 2026-07-21 03:05:26 -04:00
Add missed files from prev. commit
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@346949 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef ELF_RELOC
|
||||
#error "ELF_RELOC must be defined"
|
||||
#endif
|
||||
|
||||
ELF_RELOC(R_MSP430_NONE, 0)
|
||||
ELF_RELOC(R_MSP430_32, 1)
|
||||
ELF_RELOC(R_MSP430_10_PCREL, 2)
|
||||
ELF_RELOC(R_MSP430_16, 3)
|
||||
ELF_RELOC(R_MSP430_16_PCREL, 4)
|
||||
ELF_RELOC(R_MSP430_16_BYTE, 5)
|
||||
ELF_RELOC(R_MSP430_16_PCREL_BYTE, 6)
|
||||
ELF_RELOC(R_MSP430_2X_PCREL, 7)
|
||||
ELF_RELOC(R_MSP430_RL_PCREL, 8)
|
||||
ELF_RELOC(R_MSP430_8, 9)
|
||||
ELF_RELOC(R_MSP430_SYM_DIFF, 10)
|
||||
@@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMMSP430AsmParser
|
||||
MSP430AsmParser.cpp
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
;===- lib/Target/MSP430/AsmParser/LLVMBuild.txt ----------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = MSP430AsmParser
|
||||
parent = MSP430
|
||||
required_libraries = MC MCParser MSP430Desc MSP430Info Support
|
||||
add_to_library_groups = MSP430
|
||||
@@ -0,0 +1,563 @@
|
||||
//===- MSP430AsmParser.cpp - Parse MSP430 assembly to MCInst instructions -===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MSP430.h"
|
||||
#include "MSP430RegisterInfo.h"
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/ADT/StringSwitch.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstBuilder.h"
|
||||
#include "llvm/MC/MCParser/MCAsmLexer.h"
|
||||
#include "llvm/MC/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCParser/MCTargetAsmParser.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
#define DEBUG_TYPE "msp430-asm-parser"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Parses MSP430 assembly from a stream.
|
||||
class MSP430AsmParser : public MCTargetAsmParser {
|
||||
const MCSubtargetInfo &STI;
|
||||
MCAsmParser &Parser;
|
||||
const MCRegisterInfo *MRI;
|
||||
|
||||
bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
OperandVector &Operands, MCStreamer &Out,
|
||||
uint64_t &ErrorInfo,
|
||||
bool MatchingInlineAsm) override;
|
||||
|
||||
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
|
||||
|
||||
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
SMLoc NameLoc, OperandVector &Operands) override;
|
||||
|
||||
bool ParseDirective(AsmToken DirectiveID) override;
|
||||
|
||||
unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
|
||||
unsigned Kind) override;
|
||||
|
||||
bool parseJccInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
SMLoc NameLoc, OperandVector &Operands);
|
||||
|
||||
bool ParseOperand(OperandVector &Operands);
|
||||
|
||||
bool ParseLiteralValues(unsigned Size, SMLoc L);
|
||||
|
||||
MCAsmParser &getParser() const { return Parser; }
|
||||
MCAsmLexer &getLexer() const { return Parser.getLexer(); }
|
||||
|
||||
/// @name Auto-generated Matcher Functions
|
||||
/// {
|
||||
|
||||
#define GET_ASSEMBLER_HEADER
|
||||
#include "MSP430GenAsmMatcher.inc"
|
||||
|
||||
/// }
|
||||
|
||||
public:
|
||||
MSP430AsmParser(const MCSubtargetInfo &STI, MCAsmParser &Parser,
|
||||
const MCInstrInfo &MII, const MCTargetOptions &Options)
|
||||
: MCTargetAsmParser(Options, STI, MII), STI(STI), Parser(Parser) {
|
||||
MCAsmParserExtension::Initialize(Parser);
|
||||
MRI = getContext().getRegisterInfo();
|
||||
|
||||
setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
|
||||
}
|
||||
};
|
||||
|
||||
/// A parsed MSP430 assembly operand.
|
||||
class MSP430Operand : public MCParsedAsmOperand {
|
||||
typedef MCParsedAsmOperand Base;
|
||||
|
||||
enum KindTy {
|
||||
k_Imm,
|
||||
k_Reg,
|
||||
k_Tok,
|
||||
k_Mem,
|
||||
k_IndReg,
|
||||
k_PostIndReg
|
||||
} Kind;
|
||||
|
||||
struct Memory {
|
||||
unsigned Reg;
|
||||
const MCExpr *Offset;
|
||||
};
|
||||
union {
|
||||
const MCExpr *Imm;
|
||||
unsigned Reg;
|
||||
StringRef Tok;
|
||||
Memory Mem;
|
||||
};
|
||||
|
||||
SMLoc Start, End;
|
||||
|
||||
public:
|
||||
MSP430Operand(StringRef Tok, SMLoc const &S)
|
||||
: Base(), Kind(k_Tok), Tok(Tok), Start(S), End(S) {}
|
||||
MSP430Operand(KindTy Kind, unsigned Reg, SMLoc const &S, SMLoc const &E)
|
||||
: Base(), Kind(Kind), Reg(Reg), Start(S), End(E) {}
|
||||
MSP430Operand(MCExpr const *Imm, SMLoc const &S, SMLoc const &E)
|
||||
: Base(), Kind(k_Imm), Imm(Imm), Start(S), End(E) {}
|
||||
MSP430Operand(unsigned Reg, MCExpr const *Expr, SMLoc const &S, SMLoc const &E)
|
||||
: Base(), Kind(k_Mem), Mem({Reg, Expr}), Start(S), End(E) {}
|
||||
|
||||
void addRegOperands(MCInst &Inst, unsigned N) const {
|
||||
assert((Kind == k_Reg || Kind == k_IndReg || Kind == k_PostIndReg) &&
|
||||
"Unexpected operand kind");
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
|
||||
Inst.addOperand(MCOperand::createReg(Reg));
|
||||
}
|
||||
|
||||
void addExprOperand(MCInst &Inst, const MCExpr *Expr) const {
|
||||
// Add as immediate when possible
|
||||
if (!Expr)
|
||||
Inst.addOperand(MCOperand::createImm(0));
|
||||
else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
|
||||
Inst.addOperand(MCOperand::createImm(CE->getValue()));
|
||||
else
|
||||
Inst.addOperand(MCOperand::createExpr(Expr));
|
||||
}
|
||||
|
||||
void addImmOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(Kind == k_Imm && "Unexpected operand kind");
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
|
||||
addExprOperand(Inst, Imm);
|
||||
}
|
||||
|
||||
void addMemOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(Kind == k_Mem && "Unexpected operand kind");
|
||||
assert(N == 2 && "Invalid number of operands");
|
||||
|
||||
Inst.addOperand(MCOperand::createReg(Mem.Reg));
|
||||
addExprOperand(Inst, Mem.Offset);
|
||||
}
|
||||
|
||||
bool isReg() const { return Kind == k_Reg; }
|
||||
bool isImm() const { return Kind == k_Imm; }
|
||||
bool isToken() const { return Kind == k_Tok; }
|
||||
bool isMem() const { return Kind == k_Mem; }
|
||||
bool isIndReg() const { return Kind == k_IndReg; }
|
||||
bool isPostIndReg() const { return Kind == k_PostIndReg; }
|
||||
|
||||
bool isCGImm() const {
|
||||
if (Kind != k_Imm)
|
||||
return false;
|
||||
|
||||
int64_t Val;
|
||||
if (!Imm->evaluateAsAbsolute(Val))
|
||||
return false;
|
||||
|
||||
if (Val == 0 || Val == 1 || Val == 2 || Val == 4 || Val == 8 || Val == -1)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
StringRef getToken() const {
|
||||
assert(Kind == k_Tok && "Invalid access!");
|
||||
return Tok;
|
||||
}
|
||||
|
||||
unsigned getReg() const {
|
||||
assert(Kind == k_Reg && "Invalid access!");
|
||||
return Reg;
|
||||
}
|
||||
|
||||
void setReg(unsigned RegNo) {
|
||||
assert(Kind == k_Reg && "Invalid access!");
|
||||
Reg = RegNo;
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreateToken(StringRef Str, SMLoc S) {
|
||||
return make_unique<MSP430Operand>(Str, S);
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreateReg(unsigned RegNum, SMLoc S,
|
||||
SMLoc E) {
|
||||
return make_unique<MSP430Operand>(k_Reg, RegNum, S, E);
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreateImm(const MCExpr *Val, SMLoc S,
|
||||
SMLoc E) {
|
||||
return make_unique<MSP430Operand>(Val, S, E);
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreateMem(unsigned RegNum,
|
||||
const MCExpr *Val,
|
||||
SMLoc S, SMLoc E) {
|
||||
return make_unique<MSP430Operand>(RegNum, Val, S, E);
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreateIndReg(unsigned RegNum, SMLoc S,
|
||||
SMLoc E) {
|
||||
return make_unique<MSP430Operand>(k_IndReg, RegNum, S, E);
|
||||
}
|
||||
|
||||
static std::unique_ptr<MSP430Operand> CreatePostIndReg(unsigned RegNum, SMLoc S,
|
||||
SMLoc E) {
|
||||
return make_unique<MSP430Operand>(k_PostIndReg, RegNum, S, E);
|
||||
}
|
||||
|
||||
SMLoc getStartLoc() const { return Start; }
|
||||
SMLoc getEndLoc() const { return End; }
|
||||
|
||||
virtual void print(raw_ostream &O) const {
|
||||
switch (Kind) {
|
||||
case k_Tok:
|
||||
O << "Token " << Tok;
|
||||
break;
|
||||
case k_Reg:
|
||||
O << "Register " << Reg;
|
||||
break;
|
||||
case k_Imm:
|
||||
O << "Immediate " << *Imm;
|
||||
break;
|
||||
case k_Mem:
|
||||
O << "Memory ";
|
||||
O << *Mem.Offset << "(" << Reg << ")";
|
||||
break;
|
||||
case k_IndReg:
|
||||
O << "RegInd " << Reg;
|
||||
break;
|
||||
case k_PostIndReg:
|
||||
O << "PostInc " << Reg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
bool MSP430AsmParser::MatchAndEmitInstruction(SMLoc Loc, unsigned &Opcode,
|
||||
OperandVector &Operands,
|
||||
MCStreamer &Out,
|
||||
uint64_t &ErrorInfo,
|
||||
bool MatchingInlineAsm) {
|
||||
MCInst Inst;
|
||||
unsigned MatchResult =
|
||||
MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm);
|
||||
|
||||
switch (MatchResult) {
|
||||
case Match_Success:
|
||||
Inst.setLoc(Loc);
|
||||
Out.EmitInstruction(Inst, STI);
|
||||
return false;
|
||||
case Match_MnemonicFail:
|
||||
return Error(Loc, "invalid instruction mnemonic");
|
||||
case Match_InvalidOperand: {
|
||||
SMLoc ErrorLoc = Loc;
|
||||
if (ErrorInfo != ~0U) {
|
||||
if (ErrorInfo >= Operands.size())
|
||||
return Error(ErrorLoc, "too few operands for instruction");
|
||||
|
||||
ErrorLoc = ((MSP430Operand &)*Operands[ErrorInfo]).getStartLoc();
|
||||
if (ErrorLoc == SMLoc())
|
||||
ErrorLoc = Loc;
|
||||
}
|
||||
return Error(ErrorLoc, "invalid operand for instruction");
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-generated by TableGen
|
||||
static unsigned MatchRegisterName(StringRef Name);
|
||||
static unsigned MatchRegisterAltName(StringRef Name);
|
||||
|
||||
bool MSP430AsmParser::ParseRegister(unsigned &RegNo, SMLoc &StartLoc,
|
||||
SMLoc &EndLoc) {
|
||||
if (getLexer().getKind() == AsmToken::Identifier) {
|
||||
auto Name = getLexer().getTok().getIdentifier().lower();
|
||||
RegNo = MatchRegisterName(Name);
|
||||
if (RegNo == MSP430::NoRegister) {
|
||||
RegNo = MatchRegisterAltName(Name);
|
||||
if (RegNo == MSP430::NoRegister)
|
||||
return true;
|
||||
}
|
||||
|
||||
AsmToken const &T = getParser().getTok();
|
||||
StartLoc = T.getLoc();
|
||||
EndLoc = T.getEndLoc();
|
||||
getLexer().Lex(); // eat register token
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return Error(StartLoc, "invalid register name");
|
||||
}
|
||||
|
||||
bool MSP430AsmParser::parseJccInstruction(ParseInstructionInfo &Info,
|
||||
StringRef Name, SMLoc NameLoc,
|
||||
OperandVector &Operands) {
|
||||
if (!Name.startswith_lower("j"))
|
||||
return true;
|
||||
|
||||
auto CC = Name.drop_front().lower();
|
||||
unsigned CondCode;
|
||||
if (CC == "ne" || CC == "nz")
|
||||
CondCode = MSP430CC::COND_NE;
|
||||
else if (CC == "eq" || CC == "z")
|
||||
CondCode = MSP430CC::COND_E;
|
||||
else if (CC == "lo" || CC == "nc")
|
||||
CondCode = MSP430CC::COND_LO;
|
||||
else if (CC == "hs" || CC == "c")
|
||||
CondCode = MSP430CC::COND_HS;
|
||||
else if (CC == "n")
|
||||
CondCode = MSP430CC::COND_N;
|
||||
else if (CC == "ge")
|
||||
CondCode = MSP430CC::COND_GE;
|
||||
else if (CC == "l")
|
||||
CondCode = MSP430CC::COND_L;
|
||||
else if (CC == "mp")
|
||||
CondCode = MSP430CC::COND_NONE;
|
||||
else
|
||||
return Error(NameLoc, "unknown instruction");
|
||||
|
||||
if (CondCode == (unsigned)MSP430CC::COND_NONE)
|
||||
Operands.push_back(MSP430Operand::CreateToken("jmp", NameLoc));
|
||||
else {
|
||||
Operands.push_back(MSP430Operand::CreateToken("j", NameLoc));
|
||||
const MCExpr *CCode = MCConstantExpr::create(CondCode, getContext());
|
||||
Operands.push_back(MSP430Operand::CreateImm(CCode, SMLoc(), SMLoc()));
|
||||
}
|
||||
|
||||
// Skip optional '$' sign.
|
||||
if (getLexer().getKind() == AsmToken::Dollar)
|
||||
getLexer().Lex(); // Eat '$'
|
||||
|
||||
const MCExpr *Val;
|
||||
SMLoc ExprLoc = getLexer().getLoc();
|
||||
if (getParser().parseExpression(Val))
|
||||
return Error(ExprLoc, "expected expression operand");
|
||||
|
||||
int64_t Res;
|
||||
if (Val->evaluateAsAbsolute(Res))
|
||||
if (Res < -512 || Res > 511)
|
||||
return Error(ExprLoc, "invalid jump offset");
|
||||
|
||||
Operands.push_back(MSP430Operand::CreateImm(Val, ExprLoc,
|
||||
getLexer().getLoc()));
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
SMLoc Loc = getLexer().getLoc();
|
||||
getParser().eatToEndOfStatement();
|
||||
return Error(Loc, "unexpected token");
|
||||
}
|
||||
|
||||
getParser().Lex(); // Consume the EndOfStatement.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MSP430AsmParser::ParseInstruction(ParseInstructionInfo &Info,
|
||||
StringRef Name, SMLoc NameLoc,
|
||||
OperandVector &Operands) {
|
||||
// Drop .w suffix
|
||||
if (Name.endswith_lower(".w"))
|
||||
Name = Name.drop_back(2);
|
||||
|
||||
if (!parseJccInstruction(Info, Name, NameLoc, Operands))
|
||||
return false;
|
||||
|
||||
// First operand is instruction mnemonic
|
||||
Operands.push_back(MSP430Operand::CreateToken(Name, NameLoc));
|
||||
|
||||
// If there are no more operands, then finish
|
||||
if (getLexer().is(AsmToken::EndOfStatement))
|
||||
return false;
|
||||
|
||||
// Parse first operand
|
||||
if (ParseOperand(Operands))
|
||||
return true;
|
||||
|
||||
// Parse second operand if any
|
||||
if (getLexer().is(AsmToken::Comma)) {
|
||||
getLexer().Lex(); // Eat ','
|
||||
if (ParseOperand(Operands))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
SMLoc Loc = getLexer().getLoc();
|
||||
getParser().eatToEndOfStatement();
|
||||
return Error(Loc, "unexpected token");
|
||||
}
|
||||
|
||||
getParser().Lex(); // Consume the EndOfStatement.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MSP430AsmParser::ParseDirective(AsmToken DirectiveID) {
|
||||
StringRef IDVal = DirectiveID.getIdentifier();
|
||||
if (IDVal.lower() == ".long") {
|
||||
ParseLiteralValues(4, DirectiveID.getLoc());
|
||||
} else if (IDVal.lower() == ".word" || IDVal.lower() == ".short") {
|
||||
ParseLiteralValues(2, DirectiveID.getLoc());
|
||||
} else if (IDVal.lower() == ".byte") {
|
||||
ParseLiteralValues(1, DirectiveID.getLoc());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MSP430AsmParser::ParseOperand(OperandVector &Operands) {
|
||||
switch (getLexer().getKind()) {
|
||||
default: return true;
|
||||
case AsmToken::Identifier: {
|
||||
// try rN
|
||||
unsigned RegNo;
|
||||
SMLoc StartLoc, EndLoc;
|
||||
if (!ParseRegister(RegNo, StartLoc, EndLoc)) {
|
||||
Operands.push_back(MSP430Operand::CreateReg(RegNo, StartLoc, EndLoc));
|
||||
return false;
|
||||
}
|
||||
LLVM_FALLTHROUGH;
|
||||
}
|
||||
case AsmToken::Integer:
|
||||
case AsmToken::Plus:
|
||||
case AsmToken::Minus: {
|
||||
SMLoc StartLoc = getParser().getTok().getLoc();
|
||||
const MCExpr *Val;
|
||||
// Try constexpr[(rN)]
|
||||
if (!getParser().parseExpression(Val)) {
|
||||
unsigned RegNo = MSP430::PC;
|
||||
SMLoc EndLoc = getParser().getTok().getLoc();
|
||||
// Try (rN)
|
||||
if (getLexer().getKind() == AsmToken::LParen) {
|
||||
getLexer().Lex(); // Eat '('
|
||||
SMLoc RegStartLoc;
|
||||
if (ParseRegister(RegNo, RegStartLoc, EndLoc))
|
||||
return true;
|
||||
if (getLexer().getKind() != AsmToken::RParen)
|
||||
return true;
|
||||
EndLoc = getParser().getTok().getEndLoc();
|
||||
getLexer().Lex(); // Eat ')'
|
||||
}
|
||||
Operands.push_back(MSP430Operand::CreateMem(RegNo, Val, StartLoc,
|
||||
EndLoc));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case AsmToken::Amp: {
|
||||
// Try &constexpr
|
||||
SMLoc StartLoc = getParser().getTok().getLoc();
|
||||
getLexer().Lex(); // Eat '&'
|
||||
const MCExpr *Val;
|
||||
if (!getParser().parseExpression(Val)) {
|
||||
SMLoc EndLoc = getParser().getTok().getLoc();
|
||||
Operands.push_back(MSP430Operand::CreateMem(MSP430::SR, Val, StartLoc,
|
||||
EndLoc));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case AsmToken::At: {
|
||||
// Try @rN[+]
|
||||
SMLoc StartLoc = getParser().getTok().getLoc();
|
||||
getLexer().Lex(); // Eat '@'
|
||||
unsigned RegNo;
|
||||
SMLoc RegStartLoc, EndLoc;
|
||||
if (ParseRegister(RegNo, RegStartLoc, EndLoc))
|
||||
return true;
|
||||
if (getLexer().getKind() == AsmToken::Plus) {
|
||||
Operands.push_back(MSP430Operand::CreatePostIndReg(RegNo, StartLoc, EndLoc));
|
||||
getLexer().Lex(); // Eat '+'
|
||||
return false;
|
||||
}
|
||||
Operands.push_back(MSP430Operand::CreateIndReg(RegNo, StartLoc, EndLoc));
|
||||
return false;
|
||||
}
|
||||
case AsmToken::Hash:
|
||||
// Try #constexpr
|
||||
SMLoc StartLoc = getParser().getTok().getLoc();
|
||||
getLexer().Lex(); // Eat '#'
|
||||
const MCExpr *Val;
|
||||
if (!getParser().parseExpression(Val)) {
|
||||
SMLoc EndLoc = getParser().getTok().getLoc();
|
||||
Operands.push_back(MSP430Operand::CreateImm(Val, StartLoc, EndLoc));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool MSP430AsmParser::ParseLiteralValues(unsigned Size, SMLoc L) {
|
||||
auto parseOne = [&]() -> bool {
|
||||
const MCExpr *Value;
|
||||
if (getParser().parseExpression(Value))
|
||||
return true;
|
||||
getParser().getStreamer().EmitValue(Value, Size, L);
|
||||
return false;
|
||||
};
|
||||
return (parseMany(parseOne));
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeMSP430AsmParser() {
|
||||
RegisterMCAsmParser<MSP430AsmParser> X(getTheMSP430Target());
|
||||
}
|
||||
|
||||
#define GET_REGISTER_MATCHER
|
||||
#define GET_MATCHER_IMPLEMENTATION
|
||||
#include "MSP430GenAsmMatcher.inc"
|
||||
|
||||
static unsigned convertGR16ToGR8(unsigned Reg) {
|
||||
switch (Reg) {
|
||||
default:
|
||||
llvm_unreachable("Unknown GR16 register");
|
||||
case MSP430::PC: return MSP430::PCB;
|
||||
case MSP430::SP: return MSP430::SPB;
|
||||
case MSP430::SR: return MSP430::SRB;
|
||||
case MSP430::CG: return MSP430::CGB;
|
||||
case MSP430::FP: return MSP430::FPB;
|
||||
case MSP430::R5: return MSP430::R5B;
|
||||
case MSP430::R6: return MSP430::R6B;
|
||||
case MSP430::R7: return MSP430::R7B;
|
||||
case MSP430::R8: return MSP430::R8B;
|
||||
case MSP430::R9: return MSP430::R9B;
|
||||
case MSP430::R10: return MSP430::R10B;
|
||||
case MSP430::R11: return MSP430::R11B;
|
||||
case MSP430::R12: return MSP430::R12B;
|
||||
case MSP430::R13: return MSP430::R13B;
|
||||
case MSP430::R14: return MSP430::R14B;
|
||||
case MSP430::R15: return MSP430::R15B;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MSP430AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
|
||||
unsigned Kind) {
|
||||
MSP430Operand &Op = static_cast<MSP430Operand &>(AsmOp);
|
||||
|
||||
if (!Op.isReg())
|
||||
return Match_InvalidOperand;
|
||||
|
||||
unsigned Reg = Op.getReg();
|
||||
bool isGR16 =
|
||||
MSP430MCRegisterClasses[MSP430::GR16RegClassID].contains(Reg);
|
||||
|
||||
if (isGR16 && (Kind == MCK_GR8)) {
|
||||
Op.setReg(convertGR16ToGR8(Reg));
|
||||
return Match_Success;
|
||||
}
|
||||
|
||||
return Match_InvalidOperand;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
add_llvm_library(LLVMMSP430Disassembler
|
||||
MSP430Disassembler.cpp
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
;====- lib/Target/MSP430/Disassembler/LLVMBuild.txt ------------*- Conf -*--===;
|
||||
;
|
||||
; The LLVM Compiler Infrastructure
|
||||
;
|
||||
; This file is distributed under the University of Illinois Open Source
|
||||
; License. See LICENSE.TXT for details.
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
;
|
||||
; This is an LLVMBuild description file for the components in this subdirectory.
|
||||
;
|
||||
; For more information on the LLVMBuild system, please see:
|
||||
;
|
||||
; http://llvm.org/docs/LLVMBuild.html
|
||||
;
|
||||
;===------------------------------------------------------------------------===;
|
||||
|
||||
[component_0]
|
||||
type = Library
|
||||
name = MSP430Disassembler
|
||||
parent = MSP430
|
||||
required_libraries = MCDisassembler MSP430Info Support
|
||||
add_to_library_groups = MSP430
|
||||
@@ -0,0 +1,375 @@
|
||||
//===-- MSP430Disassembler.cpp - Disassembler for MSP430 ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MSP430Disassembler class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MSP430.h"
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDisassembler/MCDisassembler.h"
|
||||
#include "llvm/MC/MCFixedLenDisassembler.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "msp430-disassembler"
|
||||
|
||||
typedef MCDisassembler::DecodeStatus DecodeStatus;
|
||||
|
||||
namespace {
|
||||
class MSP430Disassembler : public MCDisassembler {
|
||||
DecodeStatus getInstructionI(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const;
|
||||
|
||||
DecodeStatus getInstructionII(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const;
|
||||
|
||||
DecodeStatus getInstructionCJ(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const;
|
||||
|
||||
public:
|
||||
MSP430Disassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
|
||||
: MCDisassembler(STI, Ctx) {}
|
||||
|
||||
DecodeStatus getInstruction(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes, uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const override;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
static MCDisassembler *createMSP430Disassembler(const Target &T,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx) {
|
||||
return new MSP430Disassembler(STI, Ctx);
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeMSP430Disassembler() {
|
||||
TargetRegistry::RegisterMCDisassembler(getTheMSP430Target(),
|
||||
createMSP430Disassembler);
|
||||
}
|
||||
|
||||
static const unsigned GR8DecoderTable[] = {
|
||||
MSP430::PCB, MSP430::SPB, MSP430::SRB, MSP430::CGB,
|
||||
MSP430::FPB, MSP430::R5B, MSP430::R6B, MSP430::R7B,
|
||||
MSP430::R8B, MSP430::R9B, MSP430::R10B, MSP430::R11B,
|
||||
MSP430::R12B, MSP430::R13B, MSP430::R14B, MSP430::R15B
|
||||
};
|
||||
|
||||
static DecodeStatus DecodeGR8RegisterClass(MCInst &MI, uint64_t RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
if (RegNo > 15)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
unsigned Reg = GR8DecoderTable[RegNo];
|
||||
MI.addOperand(MCOperand::createReg(Reg));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static const unsigned GR16DecoderTable[] = {
|
||||
MSP430::PC, MSP430::SP, MSP430::SR, MSP430::CG,
|
||||
MSP430::FP, MSP430::R5, MSP430::R6, MSP430::R7,
|
||||
MSP430::R8, MSP430::R9, MSP430::R10, MSP430::R11,
|
||||
MSP430::R12, MSP430::R13, MSP430::R14, MSP430::R15
|
||||
};
|
||||
|
||||
static DecodeStatus DecodeGR16RegisterClass(MCInst &MI, uint64_t RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
if (RegNo > 15)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
unsigned Reg = GR16DecoderTable[RegNo];
|
||||
MI.addOperand(MCOperand::createReg(Reg));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
|
||||
const void *Decoder);
|
||||
|
||||
static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
|
||||
uint64_t Address,
|
||||
const void *Decoder);
|
||||
|
||||
#include "MSP430GenDisassemblerTables.inc"
|
||||
|
||||
static DecodeStatus DecodeCGImm(MCInst &MI, uint64_t Bits, uint64_t Address,
|
||||
const void *Decoder) {
|
||||
int64_t Imm;
|
||||
switch (Bits) {
|
||||
default:
|
||||
llvm_unreachable("Invalid immediate value");
|
||||
case 0x22: Imm = 4; break;
|
||||
case 0x32: Imm = 8; break;
|
||||
case 0x03: Imm = 0; break;
|
||||
case 0x13: Imm = 1; break;
|
||||
case 0x23: Imm = 2; break;
|
||||
case 0x33: Imm = -1; break;
|
||||
}
|
||||
MI.addOperand(MCOperand::createImm(Imm));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeMemOperand(MCInst &MI, uint64_t Bits,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
unsigned Reg = Bits & 15;
|
||||
unsigned Imm = Bits >> 4;
|
||||
|
||||
if (DecodeGR16RegisterClass(MI, Reg, Address, Decoder) !=
|
||||
MCDisassembler::Success)
|
||||
return MCDisassembler::Fail;
|
||||
|
||||
MI.addOperand(MCOperand::createImm((int16_t)Imm));
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
enum AddrMode {
|
||||
amInvalid = 0,
|
||||
amRegister,
|
||||
amIndexed,
|
||||
amIndirect,
|
||||
amIndirectPost,
|
||||
amSymbolic,
|
||||
amImmediate,
|
||||
amAbsolute,
|
||||
amConstant
|
||||
};
|
||||
|
||||
static AddrMode DecodeSrcAddrMode(unsigned Rs, unsigned As) {
|
||||
switch (Rs) {
|
||||
case 0:
|
||||
if (As == 1) return amSymbolic;
|
||||
if (As == 2) return amInvalid;
|
||||
if (As == 3) return amImmediate;
|
||||
break;
|
||||
case 2:
|
||||
if (As == 1) return amAbsolute;
|
||||
if (As == 2) return amConstant;
|
||||
if (As == 3) return amConstant;
|
||||
break;
|
||||
case 3:
|
||||
return amConstant;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (As) {
|
||||
case 0: return amRegister;
|
||||
case 1: return amIndexed;
|
||||
case 2: return amIndirect;
|
||||
case 3: return amIndirectPost;
|
||||
default:
|
||||
llvm_unreachable("As out of range");
|
||||
}
|
||||
}
|
||||
|
||||
static AddrMode DecodeSrcAddrModeI(unsigned Insn) {
|
||||
unsigned Rs = fieldFromInstruction(Insn, 8, 4);
|
||||
unsigned As = fieldFromInstruction(Insn, 4, 2);
|
||||
return DecodeSrcAddrMode(Rs, As);
|
||||
}
|
||||
|
||||
static AddrMode DecodeSrcAddrModeII(unsigned Insn) {
|
||||
unsigned Rs = fieldFromInstruction(Insn, 0, 4);
|
||||
unsigned As = fieldFromInstruction(Insn, 4, 2);
|
||||
return DecodeSrcAddrMode(Rs, As);
|
||||
}
|
||||
|
||||
static AddrMode DecodeDstAddrMode(unsigned Insn) {
|
||||
unsigned Rd = fieldFromInstruction(Insn, 0, 4);
|
||||
unsigned Ad = fieldFromInstruction(Insn, 7, 1);
|
||||
switch (Rd) {
|
||||
case 0: return Ad ? amSymbolic : amRegister;
|
||||
case 2: return Ad ? amAbsolute : amRegister;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return Ad ? amIndexed : amRegister;
|
||||
}
|
||||
|
||||
static const uint8_t *getDecoderTable(AddrMode SrcAM, unsigned Words) {
|
||||
assert(0 < Words && Words < 4 && "Incorrect number of words");
|
||||
switch (SrcAM) {
|
||||
default:
|
||||
llvm_unreachable("Invalid addressing mode");
|
||||
case amRegister:
|
||||
assert(Words < 3 && "Incorrect number of words");
|
||||
return Words == 2 ? DecoderTableAlpha32 : DecoderTableAlpha16;
|
||||
case amConstant:
|
||||
assert(Words < 3 && "Incorrect number of words");
|
||||
return Words == 2 ? DecoderTableBeta32 : DecoderTableBeta16;
|
||||
case amIndexed:
|
||||
case amSymbolic:
|
||||
case amImmediate:
|
||||
case amAbsolute:
|
||||
assert(Words > 1 && "Incorrect number of words");
|
||||
return Words == 2 ? DecoderTableGamma32 : DecoderTableGamma48;
|
||||
case amIndirect:
|
||||
case amIndirectPost:
|
||||
assert(Words < 3 && "Incorrect number of words");
|
||||
return Words == 2 ? DecoderTableDelta32 : DecoderTableDelta16;
|
||||
}
|
||||
}
|
||||
|
||||
DecodeStatus MSP430Disassembler::getInstructionI(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const {
|
||||
uint64_t Insn = support::endian::read16le(Bytes.data());
|
||||
AddrMode SrcAM = DecodeSrcAddrModeI(Insn);
|
||||
AddrMode DstAM = DecodeDstAddrMode(Insn);
|
||||
if (SrcAM == amInvalid || DstAM == amInvalid) {
|
||||
Size = 2; // skip one word and let disassembler to try further
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
|
||||
unsigned Words = 1;
|
||||
switch (SrcAM) {
|
||||
case amIndexed:
|
||||
case amSymbolic:
|
||||
case amImmediate:
|
||||
case amAbsolute:
|
||||
Insn |= (uint64_t)support::endian::read16le(Bytes.data() + 2) << 16;
|
||||
++Words;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
switch (DstAM) {
|
||||
case amIndexed:
|
||||
case amSymbolic:
|
||||
case amAbsolute:
|
||||
Insn |= (uint64_t)support::endian::read16le(Bytes.data() + Words * 2)
|
||||
<< (Words * 16);
|
||||
++Words;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
DecodeStatus Result = decodeInstruction(getDecoderTable(SrcAM, Words), MI,
|
||||
Insn, Address, this, STI);
|
||||
if (Result != MCDisassembler::Fail) {
|
||||
Size = Words * 2;
|
||||
return Result;
|
||||
}
|
||||
|
||||
Size = 2;
|
||||
return DecodeStatus::Fail;
|
||||
}
|
||||
|
||||
DecodeStatus MSP430Disassembler::getInstructionII(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const {
|
||||
uint64_t Insn = support::endian::read16le(Bytes.data());
|
||||
AddrMode SrcAM = DecodeSrcAddrModeII(Insn);
|
||||
if (SrcAM == amInvalid) {
|
||||
Size = 2; // skip one word and let disassembler to try further
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
|
||||
unsigned Words = 1;
|
||||
switch (SrcAM) {
|
||||
case amIndexed:
|
||||
case amSymbolic:
|
||||
case amImmediate:
|
||||
case amAbsolute:
|
||||
Insn |= (uint64_t)support::endian::read16le(Bytes.data() + 2) << 16;
|
||||
++Words;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t *DecoderTable = Words == 2 ? DecoderTable32 : DecoderTable16;
|
||||
DecodeStatus Result = decodeInstruction(DecoderTable, MI, Insn, Address,
|
||||
this, STI);
|
||||
if (Result != MCDisassembler::Fail) {
|
||||
Size = Words * 2;
|
||||
return Result;
|
||||
}
|
||||
|
||||
Size = 2;
|
||||
return DecodeStatus::Fail;
|
||||
}
|
||||
|
||||
static MSP430CC::CondCodes getCondCode(unsigned Cond) {
|
||||
switch (Cond) {
|
||||
case 0: return MSP430CC::COND_NE;
|
||||
case 1: return MSP430CC::COND_E;
|
||||
case 2: return MSP430CC::COND_LO;
|
||||
case 3: return MSP430CC::COND_HS;
|
||||
case 4: return MSP430CC::COND_N;
|
||||
case 5: return MSP430CC::COND_GE;
|
||||
case 6: return MSP430CC::COND_L;
|
||||
case 7: return MSP430CC::COND_NONE;
|
||||
default:
|
||||
llvm_unreachable("Cond out of range");
|
||||
}
|
||||
}
|
||||
|
||||
DecodeStatus MSP430Disassembler::getInstructionCJ(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const {
|
||||
uint64_t Insn = support::endian::read16le(Bytes.data());
|
||||
unsigned Cond = fieldFromInstruction(Insn, 10, 3);
|
||||
unsigned Offset = fieldFromInstruction(Insn, 0, 10);
|
||||
|
||||
MI.addOperand(MCOperand::createImm(SignExtend32(Offset, 10)));
|
||||
|
||||
if (Cond == 7)
|
||||
MI.setOpcode(MSP430::JMP);
|
||||
else {
|
||||
MI.setOpcode(MSP430::JCC);
|
||||
MI.addOperand(MCOperand::createImm(getCondCode(Cond)));
|
||||
}
|
||||
|
||||
Size = 2;
|
||||
return DecodeStatus::Success;
|
||||
}
|
||||
|
||||
DecodeStatus MSP430Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
|
||||
ArrayRef<uint8_t> Bytes,
|
||||
uint64_t Address,
|
||||
raw_ostream &VStream,
|
||||
raw_ostream &CStream) const {
|
||||
if (Bytes.size() < 2) {
|
||||
Size = 0;
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
|
||||
uint64_t Insn = support::endian::read16le(Bytes.data());
|
||||
unsigned Opc = fieldFromInstruction(Insn, 13, 3);
|
||||
switch (Opc) {
|
||||
case 0:
|
||||
return getInstructionII(MI, Size, Bytes, Address, VStream, CStream);
|
||||
case 1:
|
||||
return getInstructionCJ(MI, Size, Bytes, Address, VStream, CStream);
|
||||
default:
|
||||
return getInstructionI(MI, Size, Bytes, Address, VStream, CStream);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
//===-- MSP430AsmBackend.cpp - MSP430 Assembler Backend -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/MSP430FixupKinds.h"
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/MC/MCAsmBackend.h"
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCDirectives.h"
|
||||
#include "llvm/MC/MCELFObjectWriter.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCFixupKindInfo.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class MSP430AsmBackend : public MCAsmBackend {
|
||||
uint8_t OSABI;
|
||||
|
||||
uint64_t adjustFixupValue(const MCFixup &Fixup, uint64_t Value,
|
||||
MCContext &Ctx) const;
|
||||
|
||||
public:
|
||||
MSP430AsmBackend(const MCSubtargetInfo &STI, uint8_t OSABI)
|
||||
: MCAsmBackend(support::little), OSABI(OSABI) {}
|
||||
~MSP430AsmBackend() override {}
|
||||
|
||||
void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||
const MCValue &Target, MutableArrayRef<char> Data,
|
||||
uint64_t Value, bool IsResolved,
|
||||
const MCSubtargetInfo *STI) const override;
|
||||
|
||||
std::unique_ptr<MCObjectTargetWriter>
|
||||
createObjectTargetWriter() const override {
|
||||
return createMSP430ELFObjectWriter(OSABI);
|
||||
}
|
||||
|
||||
bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value,
|
||||
const MCRelaxableFragment *DF,
|
||||
const MCAsmLayout &Layout) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool fixupNeedsRelaxationAdvanced(const MCFixup &Fixup, bool Resolved,
|
||||
uint64_t Value,
|
||||
const MCRelaxableFragment *DF,
|
||||
const MCAsmLayout &Layout,
|
||||
const bool WasForced) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned getNumFixupKinds() const override {
|
||||
return MSP430::NumTargetFixupKinds;
|
||||
}
|
||||
|
||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
|
||||
const static MCFixupKindInfo Infos[MSP430::NumTargetFixupKinds] = {
|
||||
// This table must be in the same order of enum in MSP430FixupKinds.h.
|
||||
//
|
||||
// name offset bits flags
|
||||
{"fixup_32", 0, 32, 0},
|
||||
{"fixup_10_pcrel", 0, 10, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_16", 0, 16, 0},
|
||||
{"fixup_16_pcrel", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_16_byte", 0, 16, 0},
|
||||
{"fixup_16_pcrel_byte", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_2x_pcrel", 0, 10, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_rl_pcrel", 0, 16, MCFixupKindInfo::FKF_IsPCRel},
|
||||
{"fixup_8", 0, 8, 0},
|
||||
{"fixup_sym_diff", 0, 32, 0},
|
||||
};
|
||||
static_assert((array_lengthof(Infos)) == MSP430::NumTargetFixupKinds,
|
||||
"Not all fixup kinds added to Infos array");
|
||||
|
||||
if (Kind < FirstTargetFixupKind)
|
||||
return MCAsmBackend::getFixupKindInfo(Kind);
|
||||
|
||||
return Infos[Kind - FirstTargetFixupKind];
|
||||
}
|
||||
|
||||
bool mayNeedRelaxation(const MCInst &Inst,
|
||||
const MCSubtargetInfo &STI) const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
|
||||
MCInst &Res) const override {}
|
||||
|
||||
bool writeNopData(raw_ostream &OS, uint64_t Count) const override;
|
||||
};
|
||||
|
||||
uint64_t MSP430AsmBackend::adjustFixupValue(const MCFixup &Fixup,
|
||||
uint64_t Value,
|
||||
MCContext &Ctx) const {
|
||||
unsigned Kind = Fixup.getKind();
|
||||
switch (Kind) {
|
||||
case MSP430::fixup_10_pcrel: {
|
||||
if (Value & 0x1)
|
||||
Ctx.reportError(Fixup.getLoc(), "fixup value must be 2-byte aligned");
|
||||
|
||||
// Offset is signed
|
||||
int16_t Offset = Value;
|
||||
// Jumps are in words
|
||||
Offset >>= 1;
|
||||
// PC points to the next instruction so decrement by one
|
||||
--Offset;
|
||||
|
||||
if (Offset < -512 || Offset > 511)
|
||||
Ctx.reportError(Fixup.getLoc(), "fixup value out of range");
|
||||
|
||||
// Mask 10 bits
|
||||
Offset &= 0x3ff;
|
||||
|
||||
return Offset;
|
||||
}
|
||||
default:
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
|
||||
void MSP430AsmBackend::applyFixup(const MCAssembler &Asm, const MCFixup &Fixup,
|
||||
const MCValue &Target,
|
||||
MutableArrayRef<char> Data,
|
||||
uint64_t Value, bool IsResolved,
|
||||
const MCSubtargetInfo *STI) const {
|
||||
Value = adjustFixupValue(Fixup, Value, Asm.getContext());
|
||||
MCFixupKindInfo Info = getFixupKindInfo(Fixup.getKind());
|
||||
if (!Value)
|
||||
return; // Doesn't change encoding.
|
||||
|
||||
// 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.
|
||||
for (unsigned i = 0; i != NumBytes; ++i) {
|
||||
Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
bool MSP430AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const {
|
||||
if ((Count % 2) != 0)
|
||||
return false;
|
||||
|
||||
// The canonical nop on MSP430 is mov #0, r3
|
||||
uint64_t NopCount = Count / 2;
|
||||
while (NopCount--)
|
||||
OS.write("\x03\x43", 2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
MCAsmBackend *llvm::createMSP430MCAsmBackend(const Target &T,
|
||||
const MCSubtargetInfo &STI,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCTargetOptions &Options) {
|
||||
return new MSP430AsmBackend(STI, ELF::ELFOSABI_STANDALONE);
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//===-- MSP430ELFObjectWriter.cpp - MSP430 ELF Writer ---------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MCTargetDesc/MSP430FixupKinds.h"
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
#include "llvm/MC/MCELFObjectWriter.h"
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
#include "llvm/MC/MCObjectWriter.h"
|
||||
#include "llvm/MC/MCValue.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class MSP430ELFObjectWriter : public MCELFObjectTargetWriter {
|
||||
public:
|
||||
MSP430ELFObjectWriter(uint8_t OSABI)
|
||||
: MCELFObjectTargetWriter(false, OSABI, ELF::EM_MSP430,
|
||||
/*HasRelocationAddend*/ true) {}
|
||||
|
||||
~MSP430ELFObjectWriter() override {}
|
||||
|
||||
protected:
|
||||
unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
|
||||
const MCFixup &Fixup, bool IsPCRel) const override {
|
||||
// Translate fixup kind to ELF relocation type.
|
||||
switch ((unsigned)Fixup.getKind()) {
|
||||
case FK_Data_1: return ELF::R_MSP430_8;
|
||||
case FK_Data_2: return ELF::R_MSP430_16;
|
||||
case FK_Data_4: return ELF::R_MSP430_32;
|
||||
case MSP430::fixup_32: return ELF::R_MSP430_32;
|
||||
case MSP430::fixup_10_pcrel: return ELF::R_MSP430_10_PCREL;
|
||||
case MSP430::fixup_16: return ELF::R_MSP430_16;
|
||||
case MSP430::fixup_16_pcrel: return ELF::R_MSP430_16_PCREL;
|
||||
case MSP430::fixup_16_byte: return ELF::R_MSP430_16_BYTE;
|
||||
case MSP430::fixup_16_pcrel_byte: return ELF::R_MSP430_16_PCREL_BYTE;
|
||||
case MSP430::fixup_2x_pcrel: return ELF::R_MSP430_2X_PCREL;
|
||||
case MSP430::fixup_rl_pcrel: return ELF::R_MSP430_RL_PCREL;
|
||||
case MSP430::fixup_8: return ELF::R_MSP430_8;
|
||||
case MSP430::fixup_sym_diff: return ELF::R_MSP430_SYM_DIFF;
|
||||
default:
|
||||
llvm_unreachable("Invalid fixup kind");
|
||||
}
|
||||
}
|
||||
};
|
||||
} // end of anonymous namespace
|
||||
|
||||
std::unique_ptr<MCObjectTargetWriter>
|
||||
llvm::createMSP430ELFObjectWriter(uint8_t OSABI) {
|
||||
return llvm::make_unique<MSP430ELFObjectWriter>(OSABI);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
//===-- MSP430ELFStreamer.cpp - MSP430 ELF Target Streamer Methods --------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file provides MSP430 specific target streamer methods.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MSP430MCTargetDesc.h"
|
||||
#include "llvm/BinaryFormat/ELF.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCELFStreamer.h"
|
||||
#include "llvm/MC/MCSectionELF.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MSP430TargetELFStreamer : public MCTargetStreamer {
|
||||
public:
|
||||
MCELFStreamer &getStreamer();
|
||||
MSP430TargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
|
||||
};
|
||||
|
||||
// This part is for ELF object output.
|
||||
MSP430TargetELFStreamer::MSP430TargetELFStreamer(MCStreamer &S,
|
||||
const MCSubtargetInfo &STI)
|
||||
: MCTargetStreamer(S) {
|
||||
MCAssembler &MCA = getStreamer().getAssembler();
|
||||
unsigned EFlags = MCA.getELFHeaderEFlags();
|
||||
MCA.setELFHeaderEFlags(EFlags);
|
||||
|
||||
// Emit build attributes section according to
|
||||
// MSP430 EABI (slaa534.pdf, part 13).
|
||||
MCSection *AttributeSection = getStreamer().getContext().getELFSection(
|
||||
".MSP430.attributes", ELF::SHT_MSP430_ATTRIBUTES, 0);
|
||||
Streamer.SwitchSection(AttributeSection);
|
||||
|
||||
// Format version.
|
||||
Streamer.EmitIntValue(0x41, 1);
|
||||
// Subsection length.
|
||||
Streamer.EmitIntValue(22, 4);
|
||||
// Vendor name string, zero-terminated.
|
||||
Streamer.EmitBytes("mspabi");
|
||||
Streamer.EmitIntValue(0, 1);
|
||||
|
||||
// Attribute vector scope tag. 1 stands for the entire file.
|
||||
Streamer.EmitIntValue(1, 1);
|
||||
// Attribute vector length.
|
||||
Streamer.EmitIntValue(11, 4);
|
||||
// OFBA_MSPABI_Tag_ISA(4) = 1, MSP430
|
||||
Streamer.EmitIntValue(4, 1);
|
||||
Streamer.EmitIntValue(1, 1);
|
||||
// OFBA_MSPABI_Tag_Code_Model(6) = 1, Small
|
||||
Streamer.EmitIntValue(6, 1);
|
||||
Streamer.EmitIntValue(1, 1);
|
||||
// OFBA_MSPABI_Tag_Data_Model(8) = 1, Small
|
||||
Streamer.EmitIntValue(8, 1);
|
||||
Streamer.EmitIntValue(1, 1);
|
||||
}
|
||||
|
||||
MCELFStreamer &MSP430TargetELFStreamer::getStreamer() {
|
||||
return static_cast<MCELFStreamer &>(Streamer);
|
||||
}
|
||||
|
||||
MCTargetStreamer *
|
||||
createMSP430ObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
|
||||
const Triple &TT = STI.getTargetTriple();
|
||||
if (TT.isOSBinFormatELF())
|
||||
return new MSP430TargetELFStreamer(S, STI);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
@@ -0,0 +1,53 @@
|
||||
//===-- MSP430FixupKinds.h - MSP430 Specific Fixup Entries ------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_LIB_TARGET_MSP430_MCTARGETDESC_MSP430FIXUPKINDS_H
|
||||
#define LLVM_LIB_TARGET_MSP430_MCTARGETDESC_MSP430FIXUPKINDS_H
|
||||
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
|
||||
#undef MSP430
|
||||
|
||||
namespace llvm {
|
||||
namespace MSP430 {
|
||||
|
||||
// This table must be in the same order of
|
||||
// MCFixupKindInfo Infos[MSP430::NumTargetFixupKinds]
|
||||
// in MSP430AsmBackend.cpp.
|
||||
//
|
||||
enum Fixups {
|
||||
// A 32 bit absolute fixup.
|
||||
fixup_32 = FirstTargetFixupKind,
|
||||
// A 10 bit PC relative fixup.
|
||||
fixup_10_pcrel,
|
||||
// A 16 bit absolute fixup.
|
||||
fixup_16,
|
||||
// A 16 bit PC relative fixup.
|
||||
fixup_16_pcrel,
|
||||
// A 16 bit absolute fixup for byte operations.
|
||||
fixup_16_byte,
|
||||
// A 16 bit PC relative fixup for command address.
|
||||
fixup_16_pcrel_byte,
|
||||
// A 10 bit PC relative fixup for complicated polymorphs.
|
||||
fixup_2x_pcrel,
|
||||
// A 16 bit relaxable fixup.
|
||||
fixup_rl_pcrel,
|
||||
// A 8 bit absolute fixup.
|
||||
fixup_8,
|
||||
// A 32 bit symbol difference fixup.
|
||||
fixup_sym_diff,
|
||||
|
||||
// Marker
|
||||
LastTargetFixupKind,
|
||||
NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
|
||||
};
|
||||
} // end namespace MSP430
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
//===-- MSP430MCCodeEmitter.cpp - Convert MSP430 code to machine code -----===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file implements the MSP430MCCodeEmitter class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "MSP430.h"
|
||||
#include "MCTargetDesc/MSP430MCTargetDesc.h"
|
||||
#include "MCTargetDesc/MSP430FixupKinds.h"
|
||||
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/MC/MCCodeEmitter.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCFixup.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/EndianStream.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
#define DEBUG_TYPE "mccodeemitter"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MSP430MCCodeEmitter : public MCCodeEmitter {
|
||||
MCContext &Ctx;
|
||||
MCInstrInfo const &MCII;
|
||||
|
||||
// Offset keeps track of current word number being emitted
|
||||
// inside a particular instruction.
|
||||
mutable unsigned Offset;
|
||||
|
||||
/// TableGen'erated function for getting the binary encoding for an
|
||||
/// instruction.
|
||||
uint64_t getBinaryCodeForInstr(const MCInst &MI,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
/// Returns the binary encoding of operands.
|
||||
///
|
||||
/// If an operand requires relocation, the relocation is recorded
|
||||
/// and zero is returned.
|
||||
unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
unsigned getMemOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
unsigned getPCRelImmOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
unsigned getCGImmOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
unsigned getCCOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const;
|
||||
|
||||
public:
|
||||
MSP430MCCodeEmitter(MCContext &ctx, MCInstrInfo const &MCII)
|
||||
: Ctx(ctx), MCII(MCII) {}
|
||||
|
||||
void encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const override;
|
||||
};
|
||||
|
||||
void MSP430MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
|
||||
// Get byte count of instruction.
|
||||
unsigned Size = Desc.getSize();
|
||||
|
||||
// Initialize fixup offset
|
||||
Offset = 2;
|
||||
|
||||
uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);
|
||||
size_t WordCount = Size / 2;
|
||||
|
||||
while (WordCount--) {
|
||||
support::endian::write(OS, (uint16_t)BinaryOpCode, support::little);
|
||||
BinaryOpCode >>= 16;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MSP430MCCodeEmitter::getMachineOpValue(const MCInst &MI,
|
||||
const MCOperand &MO,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
if (MO.isReg())
|
||||
return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
|
||||
|
||||
if (MO.isImm()) {
|
||||
Offset += 2;
|
||||
return MO.getImm();
|
||||
}
|
||||
|
||||
assert(MO.isExpr() && "Expected expr operand");
|
||||
Fixups.push_back(MCFixup::create(Offset, MO.getExpr(),
|
||||
static_cast<MCFixupKind>(MSP430::fixup_16_byte), MI.getLoc()));
|
||||
Offset += 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MSP430MCCodeEmitter::getMemOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO1 = MI.getOperand(Op);
|
||||
assert(MO1.isReg() && "Register operand expected");
|
||||
unsigned Reg = Ctx.getRegisterInfo()->getEncodingValue(MO1.getReg());
|
||||
|
||||
const MCOperand &MO2 = MI.getOperand(Op + 1);
|
||||
if (MO2.isImm()) {
|
||||
Offset += 2;
|
||||
return (MO2.getImm() << 4) | Reg;
|
||||
}
|
||||
|
||||
assert(MO2.isExpr() && "Expr operand expected");
|
||||
MSP430::Fixups FixupKind;
|
||||
switch (Reg) {
|
||||
case 0:
|
||||
FixupKind = MSP430::fixup_16_pcrel_byte;
|
||||
break;
|
||||
case 2:
|
||||
FixupKind = MSP430::fixup_16_byte;
|
||||
break;
|
||||
default:
|
||||
FixupKind = MSP430::fixup_16_byte;
|
||||
break;
|
||||
}
|
||||
Fixups.push_back(MCFixup::create(Offset, MO2.getExpr(),
|
||||
static_cast<MCFixupKind>(FixupKind), MI.getLoc()));
|
||||
Offset += 2;
|
||||
return Reg;
|
||||
}
|
||||
|
||||
unsigned MSP430MCCodeEmitter::getPCRelImmOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO = MI.getOperand(Op);
|
||||
if (MO.isImm())
|
||||
return MO.getImm();
|
||||
|
||||
assert(MO.isExpr() && "Expr operand expected");
|
||||
Fixups.push_back(MCFixup::create(0, MO.getExpr(),
|
||||
static_cast<MCFixupKind>(MSP430::fixup_10_pcrel), MI.getLoc()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned MSP430MCCodeEmitter::getCGImmOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO = MI.getOperand(Op);
|
||||
assert(MO.isImm() && "Expr operand expected");
|
||||
|
||||
int64_t Imm = MO.getImm();
|
||||
switch (Imm) {
|
||||
default:
|
||||
llvm_unreachable("Invalid immediate value");
|
||||
case 4: return 0x22;
|
||||
case 8: return 0x32;
|
||||
case 0: return 0x03;
|
||||
case 1: return 0x13;
|
||||
case 2: return 0x23;
|
||||
case -1: return 0x33;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned MSP430MCCodeEmitter::getCCOpValue(const MCInst &MI, unsigned Op,
|
||||
SmallVectorImpl<MCFixup> &Fixups,
|
||||
const MCSubtargetInfo &STI) const {
|
||||
const MCOperand &MO = MI.getOperand(Op);
|
||||
assert(MO.isImm() && "Immediate operand expected");
|
||||
switch (MO.getImm()) {
|
||||
case MSP430CC::COND_NE: return 0;
|
||||
case MSP430CC::COND_E: return 1;
|
||||
case MSP430CC::COND_LO: return 2;
|
||||
case MSP430CC::COND_HS: return 3;
|
||||
case MSP430CC::COND_N: return 4;
|
||||
case MSP430CC::COND_GE: return 5;
|
||||
case MSP430CC::COND_L: return 6;
|
||||
default:
|
||||
llvm_unreachable("Unknown condition code");
|
||||
}
|
||||
}
|
||||
|
||||
MCCodeEmitter *createMSP430MCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
MCContext &Ctx) {
|
||||
return new MSP430MCCodeEmitter(Ctx, MCII);
|
||||
}
|
||||
|
||||
#include "MSP430GenMCCodeEmitter.inc"
|
||||
|
||||
} // end of namespace llvm
|
||||
Reference in New Issue
Block a user