diff options
Diffstat (limited to 'llvm/lib')
11 files changed, 1572 insertions, 0 deletions
diff --git a/llvm/lib/Target/MSP430/AsmParser/CMakeLists.txt b/llvm/lib/Target/MSP430/AsmParser/CMakeLists.txt new file mode 100644 index 00000000000..bb484898afa --- /dev/null +++ b/llvm/lib/Target/MSP430/AsmParser/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMMSP430AsmParser + MSP430AsmParser.cpp +) diff --git a/llvm/lib/Target/MSP430/AsmParser/LLVMBuild.txt b/llvm/lib/Target/MSP430/AsmParser/LLVMBuild.txt new file mode 100644 index 00000000000..58f67c07db1 --- /dev/null +++ b/llvm/lib/Target/MSP430/AsmParser/LLVMBuild.txt @@ -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 diff --git a/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp new file mode 100644 index 00000000000..51b6918105e --- /dev/null +++ b/llvm/lib/Target/MSP430/AsmParser/MSP430AsmParser.cpp @@ -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; +} diff --git a/llvm/lib/Target/MSP430/Disassembler/CMakeLists.txt b/llvm/lib/Target/MSP430/Disassembler/CMakeLists.txt new file mode 100644 index 00000000000..bc33b906772 --- /dev/null +++ b/llvm/lib/Target/MSP430/Disassembler/CMakeLists.txt @@ -0,0 +1,3 @@ +add_llvm_library(LLVMMSP430Disassembler + MSP430Disassembler.cpp + ) diff --git a/llvm/lib/Target/MSP430/Disassembler/LLVMBuild.txt b/llvm/lib/Target/MSP430/Disassembler/LLVMBuild.txt new file mode 100644 index 00000000000..8af9cd9c222 --- /dev/null +++ b/llvm/lib/Target/MSP430/Disassembler/LLVMBuild.txt @@ -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 diff --git a/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp new file mode 100644 index 00000000000..2a66b4ed7f2 --- /dev/null +++ b/llvm/lib/Target/MSP430/Disassembler/MSP430Disassembler.cpp @@ -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); + } +} diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430AsmBackend.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430AsmBackend.cpp new file mode 100644 index 00000000000..bd69a9d8d79 --- /dev/null +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430AsmBackend.cpp @@ -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); +} diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFObjectWriter.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFObjectWriter.cpp new file mode 100644 index 00000000000..30d077b5b58 --- /dev/null +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFObjectWriter.cpp @@ -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); +} diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFStreamer.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFStreamer.cpp new file mode 100644 index 00000000000..9449cb27802 --- /dev/null +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430ELFStreamer.cpp @@ -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 diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430FixupKinds.h b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430FixupKinds.h new file mode 100644 index 00000000000..1eb6a275942 --- /dev/null +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430FixupKinds.h @@ -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 diff --git a/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp new file mode 100644 index 00000000000..adf2384f6e9 --- /dev/null +++ b/llvm/lib/Target/MSP430/MCTargetDesc/MSP430MCCodeEmitter.cpp @@ -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 |

