211 lines
7.2 KiB
C++
211 lines
7.2 KiB
C++
|
//===-- MSP430MCCodeEmitter.cpp - Convert MSP430 code to machine code -----===//
|
||
|
//
|
||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
//
|
||
|
// This 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 ((unsigned)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
|