|  | //===-- MBlazeMCCodeEmitter.cpp - Convert MBlaze 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 MBlazeMCCodeEmitter class. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #define DEBUG_TYPE "mblaze-emitter" | 
|  | #include "MBlaze.h" | 
|  | #include "MBlazeInstrInfo.h" | 
|  | #include "MBlazeFixupKinds.h" | 
|  | #include "llvm/MC/MCCodeEmitter.h" | 
|  | #include "llvm/MC/MCExpr.h" | 
|  | #include "llvm/MC/MCInst.h" | 
|  | #include "llvm/MC/MCSymbol.h" | 
|  | #include "llvm/MC/MCFixup.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | using namespace llvm; | 
|  |  | 
|  | STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); | 
|  |  | 
|  | namespace { | 
|  | class MBlazeMCCodeEmitter : public MCCodeEmitter { | 
|  | MBlazeMCCodeEmitter(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT | 
|  | void operator=(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT | 
|  | const TargetMachine &TM; | 
|  | const TargetInstrInfo &TII; | 
|  | MCContext &Ctx; | 
|  |  | 
|  | public: | 
|  | MBlazeMCCodeEmitter(TargetMachine &tm, MCContext &ctx) | 
|  | : TM(tm), TII(*TM.getInstrInfo()), Ctx(ctx) { | 
|  | } | 
|  |  | 
|  | ~MBlazeMCCodeEmitter() {} | 
|  |  | 
|  | // getBinaryCodeForInstr - TableGen'erated function for getting the | 
|  | // binary encoding for an instruction. | 
|  | unsigned getBinaryCodeForInstr(const MCInst &MI) const; | 
|  |  | 
|  | /// getMachineOpValue - Return binary encoding of operand. If the machine | 
|  | /// operand requires relocation, record the relocation and return zero. | 
|  | unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const; | 
|  | unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const { | 
|  | return getMachineOpValue(MI, MI.getOperand(OpIdx)); | 
|  | } | 
|  |  | 
|  | unsigned getNumFixupKinds() const { | 
|  | return 2; | 
|  | } | 
|  |  | 
|  | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { | 
|  | const static MCFixupKindInfo Infos[] = { | 
|  | { "reloc_pcrel_4byte", 0, 4 * 8, MCFixupKindInfo::FKF_IsPCRel }, | 
|  | { "reloc_pcrel_2byte", 0, 2 * 8, MCFixupKindInfo::FKF_IsPCRel } }; | 
|  |  | 
|  | if (Kind < FirstTargetFixupKind) | 
|  | return MCCodeEmitter::getFixupKindInfo(Kind); | 
|  |  | 
|  | if (unsigned(Kind-FirstTargetFixupKind) < getNumFixupKinds()) | 
|  | return Infos[Kind - FirstTargetFixupKind]; | 
|  |  | 
|  | assert(0 && "Invalid fixup kind."); | 
|  | return Infos[0]; | 
|  | } | 
|  |  | 
|  | static unsigned GetMBlazeRegNum(const MCOperand &MO) { | 
|  | // FIXME: getMBlazeRegisterNumbering() is sufficient? | 
|  | assert(0 && "MBlazeMCCodeEmitter::GetMBlazeRegNum() not yet implemented."); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { | 
|  | // The MicroBlaze uses a bit reversed format so we need to reverse the | 
|  | // order of the bits. Taken from: | 
|  | // http://graphics.stanford.edu/~seander/bithacks.html | 
|  | C = ((C * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; | 
|  |  | 
|  | OS << (char)C; | 
|  | ++CurByte; | 
|  | } | 
|  |  | 
|  | void EmitRawByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { | 
|  | OS << (char)C; | 
|  | ++CurByte; | 
|  | } | 
|  |  | 
|  | void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte, | 
|  | raw_ostream &OS) const { | 
|  | assert(Size <= 8 && "size too big in emit constant" ); | 
|  |  | 
|  | for (unsigned i = 0; i != Size; ++i) { | 
|  | EmitByte(Val & 255, CurByte, OS); | 
|  | Val >>= 8; | 
|  | } | 
|  | } | 
|  |  | 
|  | void EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const; | 
|  |  | 
|  | void EmitImmediate(const MCInst &MI, | 
|  | unsigned opNo, MCFixupKind FixupKind, | 
|  | unsigned &CurByte, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups) const; | 
|  |  | 
|  | void EncodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups) const; | 
|  | }; | 
|  |  | 
|  | } // end anonymous namespace | 
|  |  | 
|  |  | 
|  | MCCodeEmitter *llvm::createMBlazeMCCodeEmitter(const Target &, | 
|  | TargetMachine &TM, | 
|  | MCContext &Ctx) { | 
|  | return new MBlazeMCCodeEmitter(TM, Ctx); | 
|  | } | 
|  |  | 
|  | /// getMachineOpValue - Return binary encoding of operand. If the machine | 
|  | /// operand requires relocation, record the relocation and return zero. | 
|  | unsigned MBlazeMCCodeEmitter::getMachineOpValue(const MCInst &MI, | 
|  | const MCOperand &MO) const { | 
|  | if (MO.isReg()) | 
|  | return MBlazeRegisterInfo::getRegisterNumbering(MO.getReg()); | 
|  | else if (MO.isImm()) | 
|  | return static_cast<unsigned>(MO.getImm()); | 
|  | else if (MO.isExpr() ) | 
|  | return 0; // The relocation has already been recorded at this point. | 
|  | else { | 
|  | #ifndef NDEBUG | 
|  | errs() << MO; | 
|  | #endif | 
|  | llvm_unreachable(0); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | void MBlazeMCCodeEmitter:: | 
|  | EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const { | 
|  | int32_t val = (int32_t)imm.getImm(); | 
|  | if (val > 32767 || val < -32678 ) { | 
|  | EmitByte(0x0D, CurByte, OS); | 
|  | EmitByte(0x00, CurByte, OS); | 
|  | EmitRawByte((val >> 24) & 0xFF, CurByte, OS); | 
|  | EmitRawByte((val >> 16) & 0xFF, CurByte, OS); | 
|  | } | 
|  | } | 
|  |  | 
|  | void MBlazeMCCodeEmitter:: | 
|  | EmitImmediate(const MCInst &MI, unsigned opNo, MCFixupKind FixupKind, | 
|  | unsigned &CurByte, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups) const { | 
|  | assert( MI.getNumOperands()>opNo && "Not enought operands for instruction" ); | 
|  |  | 
|  | MCOperand oper = MI.getOperand(opNo); | 
|  | if (oper.isImm()) { | 
|  | EmitIMM( oper, CurByte, OS ); | 
|  | } else if (oper.isExpr()) { | 
|  | Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void MBlazeMCCodeEmitter:: | 
|  | EncodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | SmallVectorImpl<MCFixup> &Fixups) const { | 
|  | unsigned Opcode = MI.getOpcode(); | 
|  | const TargetInstrDesc &Desc = TII.get(Opcode); | 
|  | uint64_t TSFlags = Desc.TSFlags; | 
|  | // Keep track of the current byte being emitted. | 
|  | unsigned CurByte = 0; | 
|  |  | 
|  | switch ((TSFlags & MBlazeII::FormMask)) { | 
|  | default: break; | 
|  | case MBlazeII::Pseudo: | 
|  | // Pseudo instructions don't get encoded. | 
|  | return; | 
|  |  | 
|  | case MBlazeII::RegRegImm: | 
|  | EmitImmediate( MI, 2, FK_Data_4, CurByte, OS, Fixups ); | 
|  | break; | 
|  |  | 
|  | case MBlazeII::RegImmReg: | 
|  | EmitImmediate( MI, 1, FK_Data_4, CurByte, OS, Fixups ); | 
|  | break; | 
|  |  | 
|  | case MBlazeII::RegImm: | 
|  | EmitImmediate( MI, 1, MCFixupKind(MBlaze::reloc_pcrel_2byte), CurByte, OS, | 
|  | Fixups ); | 
|  | break; | 
|  |  | 
|  | case MBlazeII::Imm: | 
|  | EmitImmediate( MI, 0, MCFixupKind(MBlaze::reloc_pcrel_4byte), CurByte, OS, | 
|  | Fixups ); | 
|  | break; | 
|  | } | 
|  |  | 
|  | ++MCNumEmitted;  // Keep track of the # of mi's emitted | 
|  | unsigned Value = getBinaryCodeForInstr(MI); | 
|  | switch (Opcode) { | 
|  | default: | 
|  | EmitConstant(Value, 4, CurByte, OS); | 
|  | break; | 
|  |  | 
|  | case MBlaze::BRI: | 
|  | case MBlaze::BRAI: | 
|  | case MBlaze::BRID: | 
|  | case MBlaze::BRAID: | 
|  | case MBlaze::BRLID: | 
|  | case MBlaze::BRALID: | 
|  | MCOperand op = MI.getOperand(0); | 
|  | if (op.isExpr()) { | 
|  | EmitByte(0x0D, CurByte, OS); | 
|  | EmitByte(0x00, CurByte, OS); | 
|  | EmitRawByte(0, CurByte, OS); | 
|  | EmitRawByte(0, CurByte, OS); | 
|  | } | 
|  | EmitConstant(Value, 4, CurByte, OS); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // FIXME: These #defines shouldn't be necessary. Instead, tblgen should | 
|  | // be able to generate code emitter helpers for either variant, like it | 
|  | // does for the AsmWriter. | 
|  | #define MBlazeCodeEmitter MBlazeMCCodeEmitter | 
|  | #define MachineInstr MCInst | 
|  | #include "MBlazeGenCodeEmitter.inc" | 
|  | #undef MBlazeCodeEmitter | 
|  | #undef MachineInstr |