| Wesley Peck | c16f77f | 2010-10-21 03:57:26 +0000 | [diff] [blame^] | 1 | //===-- MBlazeMCCodeEmitter.cpp - Convert MBlaze code to machine code -----===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 | // | 
|  | 10 | // This file implements the MBlazeMCCodeEmitter class. | 
|  | 11 | // | 
|  | 12 | //===----------------------------------------------------------------------===// | 
|  | 13 |  | 
|  | 14 | #define DEBUG_TYPE "mblaze-emitter" | 
|  | 15 | #include "MBlaze.h" | 
|  | 16 | #include "MBlazeInstrInfo.h" | 
|  | 17 | #include "MBlazeFixupKinds.h" | 
|  | 18 | #include "llvm/MC/MCCodeEmitter.h" | 
|  | 19 | #include "llvm/MC/MCExpr.h" | 
|  | 20 | #include "llvm/MC/MCInst.h" | 
|  | 21 | #include "llvm/MC/MCSymbol.h" | 
|  | 22 | #include "llvm/MC/MCFixup.h" | 
|  | 23 | #include "llvm/ADT/Statistic.h" | 
|  | 24 | #include "llvm/Support/raw_ostream.h" | 
|  | 25 | using namespace llvm; | 
|  | 26 |  | 
|  | 27 | STATISTIC(MCNumEmitted, "Number of MC instructions emitted"); | 
|  | 28 |  | 
|  | 29 | namespace { | 
|  | 30 | class MBlazeMCCodeEmitter : public MCCodeEmitter { | 
|  | 31 | MBlazeMCCodeEmitter(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT | 
|  | 32 | void operator=(const MBlazeMCCodeEmitter &); // DO NOT IMPLEMENT | 
|  | 33 | const TargetMachine &TM; | 
|  | 34 | const TargetInstrInfo &TII; | 
|  | 35 | MCContext &Ctx; | 
|  | 36 |  | 
|  | 37 | public: | 
|  | 38 | MBlazeMCCodeEmitter(TargetMachine &tm, MCContext &ctx) | 
|  | 39 | : TM(tm), TII(*TM.getInstrInfo()), Ctx(ctx) { | 
|  | 40 | } | 
|  | 41 |  | 
|  | 42 | ~MBlazeMCCodeEmitter() {} | 
|  | 43 |  | 
|  | 44 | // getBinaryCodeForInstr - TableGen'erated function for getting the | 
|  | 45 | // binary encoding for an instruction. | 
|  | 46 | unsigned getBinaryCodeForInstr(const MCInst &MI) const; | 
|  | 47 |  | 
|  | 48 | /// getMachineOpValue - Return binary encoding of operand. If the machine | 
|  | 49 | /// operand requires relocation, record the relocation and return zero. | 
|  | 50 | unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const; | 
|  | 51 | unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const { | 
|  | 52 | return getMachineOpValue(MI, MI.getOperand(OpIdx)); | 
|  | 53 | } | 
|  | 54 |  | 
|  | 55 | unsigned getNumFixupKinds() const { | 
|  | 56 | return 2; | 
|  | 57 | } | 
|  | 58 |  | 
|  | 59 | const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const { | 
|  | 60 | const static MCFixupKindInfo Infos[] = { | 
|  | 61 | { "reloc_pcrel_4byte", 0, 4 * 8, MCFixupKindInfo::FKF_IsPCRel }, | 
|  | 62 | { "reloc_pcrel_2byte", 0, 2 * 8, MCFixupKindInfo::FKF_IsPCRel } }; | 
|  | 63 |  | 
|  | 64 | if (Kind < FirstTargetFixupKind) | 
|  | 65 | return MCCodeEmitter::getFixupKindInfo(Kind); | 
|  | 66 |  | 
|  | 67 | if (unsigned(Kind-FirstTargetFixupKind) < getNumFixupKinds()) | 
|  | 68 | return Infos[Kind - FirstTargetFixupKind]; | 
|  | 69 |  | 
|  | 70 | assert(0 && "Invalid fixup kind."); | 
|  | 71 | return Infos[0]; | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | static unsigned GetMBlazeRegNum(const MCOperand &MO) { | 
|  | 75 | // FIXME: getMBlazeRegisterNumbering() is sufficient? | 
|  | 76 | assert(0 && "MBlazeMCCodeEmitter::GetMBlazeRegNum() not yet implemented."); | 
|  | 77 | return 0; | 
|  | 78 | } | 
|  | 79 |  | 
|  | 80 | void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { | 
|  | 81 | // The MicroBlaze uses a bit reversed format so we need to reverse the | 
|  | 82 | // order of the bits. Taken from: | 
|  | 83 | // http://graphics.stanford.edu/~seander/bithacks.html | 
|  | 84 | C = ((C * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; | 
|  | 85 |  | 
|  | 86 | OS << (char)C; | 
|  | 87 | ++CurByte; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | void EmitRawByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const { | 
|  | 91 | OS << (char)C; | 
|  | 92 | ++CurByte; | 
|  | 93 | } | 
|  | 94 |  | 
|  | 95 | void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte, | 
|  | 96 | raw_ostream &OS) const { | 
|  | 97 | assert(Size <= 8 && "size too big in emit constant" ); | 
|  | 98 |  | 
|  | 99 | for (unsigned i = 0; i != Size; ++i) { | 
|  | 100 | EmitByte(Val & 255, CurByte, OS); | 
|  | 101 | Val >>= 8; | 
|  | 102 | } | 
|  | 103 | } | 
|  | 104 |  | 
|  | 105 | void EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const; | 
|  | 106 |  | 
|  | 107 | void EmitImmediate(const MCInst &MI, | 
|  | 108 | unsigned opNo, MCFixupKind FixupKind, | 
|  | 109 | unsigned &CurByte, raw_ostream &OS, | 
|  | 110 | SmallVectorImpl<MCFixup> &Fixups) const; | 
|  | 111 |  | 
|  | 112 | void EncodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | 113 | SmallVectorImpl<MCFixup> &Fixups) const; | 
|  | 114 | }; | 
|  | 115 |  | 
|  | 116 | } // end anonymous namespace | 
|  | 117 |  | 
|  | 118 |  | 
|  | 119 | MCCodeEmitter *llvm::createMBlazeMCCodeEmitter(const Target &, | 
|  | 120 | TargetMachine &TM, | 
|  | 121 | MCContext &Ctx) { | 
|  | 122 | return new MBlazeMCCodeEmitter(TM, Ctx); | 
|  | 123 | } | 
|  | 124 |  | 
|  | 125 | /// getMachineOpValue - Return binary encoding of operand. If the machine | 
|  | 126 | /// operand requires relocation, record the relocation and return zero. | 
|  | 127 | unsigned MBlazeMCCodeEmitter::getMachineOpValue(const MCInst &MI, | 
|  | 128 | const MCOperand &MO) const { | 
|  | 129 | if (MO.isReg()) | 
|  | 130 | return MBlazeRegisterInfo::getRegisterNumbering(MO.getReg()); | 
|  | 131 | else if (MO.isImm()) | 
|  | 132 | return static_cast<unsigned>(MO.getImm()); | 
|  | 133 | else if (MO.isExpr() ) | 
|  | 134 | return 0; // The relocation has already been recorded at this point. | 
|  | 135 | else { | 
|  | 136 | #ifndef NDEBUG | 
|  | 137 | errs() << MO; | 
|  | 138 | #endif | 
|  | 139 | llvm_unreachable(0); | 
|  | 140 | } | 
|  | 141 | return 0; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | void MBlazeMCCodeEmitter:: | 
|  | 145 | EmitIMM(const MCOperand &imm, unsigned &CurByte, raw_ostream &OS) const { | 
|  | 146 | int32_t val = (int32_t)imm.getImm(); | 
|  | 147 | if (val > 32767 || val < -32678 ) { | 
|  | 148 | EmitByte(0x0D, CurByte, OS); | 
|  | 149 | EmitByte(0x00, CurByte, OS); | 
|  | 150 | EmitRawByte((val >> 24) & 0xFF, CurByte, OS); | 
|  | 151 | EmitRawByte((val >> 16) & 0xFF, CurByte, OS); | 
|  | 152 | } | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | void MBlazeMCCodeEmitter:: | 
|  | 156 | EmitImmediate(const MCInst &MI, unsigned opNo, MCFixupKind FixupKind, | 
|  | 157 | unsigned &CurByte, raw_ostream &OS, | 
|  | 158 | SmallVectorImpl<MCFixup> &Fixups) const { | 
|  | 159 | assert( MI.getNumOperands()>opNo && "Not enought operands for instruction" ); | 
|  | 160 |  | 
|  | 161 | MCOperand oper = MI.getOperand(opNo); | 
|  | 162 | if (oper.isImm()) { | 
|  | 163 | EmitIMM( oper, CurByte, OS ); | 
|  | 164 | } else if (oper.isExpr()) { | 
|  | 165 | Fixups.push_back(MCFixup::Create(0,oper.getExpr(),FixupKind)); | 
|  | 166 | } | 
|  | 167 | } | 
|  | 168 |  | 
|  | 169 | void MBlazeMCCodeEmitter:: | 
|  | 170 | EncodeInstruction(const MCInst &MI, raw_ostream &OS, | 
|  | 171 | SmallVectorImpl<MCFixup> &Fixups) const { | 
|  | 172 | unsigned Opcode = MI.getOpcode(); | 
|  | 173 | const TargetInstrDesc &Desc = TII.get(Opcode); | 
|  | 174 | uint64_t TSFlags = Desc.TSFlags; | 
|  | 175 | // Keep track of the current byte being emitted. | 
|  | 176 | unsigned CurByte = 0; | 
|  | 177 |  | 
|  | 178 | switch ((TSFlags & MBlazeII::FormMask)) { | 
|  | 179 | default: break; | 
|  | 180 | case MBlazeII::Pseudo: | 
|  | 181 | // Pseudo instructions don't get encoded. | 
|  | 182 | return; | 
|  | 183 |  | 
|  | 184 | case MBlazeII::RegRegImm: | 
|  | 185 | EmitImmediate( MI, 2, FK_Data_4, CurByte, OS, Fixups ); | 
|  | 186 | break; | 
|  | 187 |  | 
|  | 188 | case MBlazeII::RegImmReg: | 
|  | 189 | EmitImmediate( MI, 1, FK_Data_4, CurByte, OS, Fixups ); | 
|  | 190 | break; | 
|  | 191 |  | 
|  | 192 | case MBlazeII::RegImm: | 
|  | 193 | EmitImmediate( MI, 1, MCFixupKind(MBlaze::reloc_pcrel_2byte), CurByte, OS, | 
|  | 194 | Fixups ); | 
|  | 195 | break; | 
|  | 196 |  | 
|  | 197 | case MBlazeII::Imm: | 
|  | 198 | EmitImmediate( MI, 0, MCFixupKind(MBlaze::reloc_pcrel_4byte), CurByte, OS, | 
|  | 199 | Fixups ); | 
|  | 200 | break; | 
|  | 201 | } | 
|  | 202 |  | 
|  | 203 | ++MCNumEmitted;  // Keep track of the # of mi's emitted | 
|  | 204 | unsigned Value = getBinaryCodeForInstr(MI); | 
|  | 205 | switch (Opcode) { | 
|  | 206 | default: | 
|  | 207 | EmitConstant(Value, 4, CurByte, OS); | 
|  | 208 | break; | 
|  | 209 |  | 
|  | 210 | case MBlaze::BRI: | 
|  | 211 | case MBlaze::BRAI: | 
|  | 212 | case MBlaze::BRID: | 
|  | 213 | case MBlaze::BRAID: | 
|  | 214 | case MBlaze::BRLID: | 
|  | 215 | case MBlaze::BRALID: | 
|  | 216 | MCOperand op = MI.getOperand(0); | 
|  | 217 | if (op.isExpr()) { | 
|  | 218 | EmitByte(0x0D, CurByte, OS); | 
|  | 219 | EmitByte(0x00, CurByte, OS); | 
|  | 220 | EmitRawByte(0, CurByte, OS); | 
|  | 221 | EmitRawByte(0, CurByte, OS); | 
|  | 222 | } | 
|  | 223 | EmitConstant(Value, 4, CurByte, OS); | 
|  | 224 | break; | 
|  | 225 | } | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | // FIXME: These #defines shouldn't be necessary. Instead, tblgen should | 
|  | 229 | // be able to generate code emitter helpers for either variant, like it | 
|  | 230 | // does for the AsmWriter. | 
|  | 231 | #define MBlazeCodeEmitter MBlazeMCCodeEmitter | 
|  | 232 | #define MachineInstr MCInst | 
|  | 233 | #include "MBlazeGenCodeEmitter.inc" | 
|  | 234 | #undef MBlazeCodeEmitter | 
|  | 235 | #undef MachineInstr |