blob: ad87b386d3d1a4b453cde41c26f9a22e901251f7 [file] [log] [blame]
Jim Grosbach568eeed2010-09-17 18:46:17 +00001//===-- ARM/ARMMCCodeEmitter.cpp - Convert ARM 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 ARMMCCodeEmitter class.
11//
12//===----------------------------------------------------------------------===//
13
14#define DEBUG_TYPE "arm-emitter"
15#include "ARM.h"
Jim Grosbach42fac8e2010-10-11 23:16:21 +000016#include "ARMAddressingModes.h"
Jim Grosbachd6d4b422010-10-07 22:12:50 +000017#include "ARMInstrInfo.h"
Jim Grosbach568eeed2010-09-17 18:46:17 +000018#include "llvm/MC/MCCodeEmitter.h"
19#include "llvm/MC/MCExpr.h"
20#include "llvm/MC/MCInst.h"
Jim Grosbachd6d4b422010-10-07 22:12:50 +000021#include "llvm/ADT/Statistic.h"
Jim Grosbach568eeed2010-09-17 18:46:17 +000022#include "llvm/Support/raw_ostream.h"
23using namespace llvm;
24
Jim Grosbachd6d4b422010-10-07 22:12:50 +000025STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
26
Jim Grosbach568eeed2010-09-17 18:46:17 +000027namespace {
28class ARMMCCodeEmitter : public MCCodeEmitter {
29 ARMMCCodeEmitter(const ARMMCCodeEmitter &); // DO NOT IMPLEMENT
30 void operator=(const ARMMCCodeEmitter &); // DO NOT IMPLEMENT
31 const TargetMachine &TM;
32 const TargetInstrInfo &TII;
33 MCContext &Ctx;
34
35public:
36 ARMMCCodeEmitter(TargetMachine &tm, MCContext &ctx)
37 : TM(tm), TII(*TM.getInstrInfo()), Ctx(ctx) {
Jim Grosbach568eeed2010-09-17 18:46:17 +000038 }
39
40 ~ARMMCCodeEmitter() {}
41
Jim Grosbach9af82ba2010-10-07 21:57:55 +000042 // getBinaryCodeForInstr - TableGen'erated function for getting the
43 // binary encoding for an instruction.
Jim Grosbachbade37b2010-10-08 00:21:28 +000044 unsigned getBinaryCodeForInstr(const MCInst &MI) const;
Jim Grosbach9af82ba2010-10-07 21:57:55 +000045
46 /// getMachineOpValue - Return binary encoding of operand. If the machine
47 /// operand requires relocation, record the relocation and return zero.
Jim Grosbach3e094132010-10-08 17:45:54 +000048 unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const;
49 unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const {
Jim Grosbach9af82ba2010-10-07 21:57:55 +000050 return getMachineOpValue(MI, MI.getOperand(OpIdx));
51 }
52
Jim Grosbach568eeed2010-09-17 18:46:17 +000053 unsigned getNumFixupKinds() const {
54 assert(0 && "ARMMCCodeEmitter::getNumFixupKinds() not yet implemented.");
Michael J. Spencer895dda62010-09-18 17:54:37 +000055 return 0;
Jim Grosbach568eeed2010-09-17 18:46:17 +000056 }
57
58 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
59 static MCFixupKindInfo rtn;
60 assert(0 && "ARMMCCodeEmitter::getFixupKindInfo() not yet implemented.");
61 return rtn;
62 }
63
64 static unsigned GetARMRegNum(const MCOperand &MO) {
65 // FIXME: getARMRegisterNumbering() is sufficient?
66 assert(0 && "ARMMCCodeEmitter::GetARMRegNum() not yet implemented.");
67 return 0;
68 }
69
70 void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const {
71 OS << (char)C;
72 ++CurByte;
73 }
74
75 void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
76 raw_ostream &OS) const {
77 // Output the constant in little endian byte order.
78 for (unsigned i = 0; i != Size; ++i) {
79 EmitByte(Val & 255, CurByte, OS);
80 Val >>= 8;
81 }
82 }
83
84 void EmitImmediate(const MCOperand &Disp,
85 unsigned ImmSize, MCFixupKind FixupKind,
86 unsigned &CurByte, raw_ostream &OS,
87 SmallVectorImpl<MCFixup> &Fixups,
88 int ImmOffset = 0) const;
89
90 void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
91 SmallVectorImpl<MCFixup> &Fixups) const;
Jim Grosbach568eeed2010-09-17 18:46:17 +000092};
93
94} // end anonymous namespace
95
96
97MCCodeEmitter *llvm::createARMMCCodeEmitter(const Target &,
98 TargetMachine &TM,
99 MCContext &Ctx) {
100 return new ARMMCCodeEmitter(TM, Ctx);
101}
102
103void ARMMCCodeEmitter::
104EmitImmediate(const MCOperand &DispOp, unsigned Size, MCFixupKind FixupKind,
105 unsigned &CurByte, raw_ostream &OS,
106 SmallVectorImpl<MCFixup> &Fixups, int ImmOffset) const {
107 assert(0 && "ARMMCCodeEmitter::EmitImmediate() not yet implemented.");
108}
109
Jim Grosbach56ac9072010-10-08 21:45:55 +0000110/// getMachineOpValue - Return binary encoding of operand. If the machine
111/// operand requires relocation, record the relocation and return zero.
112unsigned ARMMCCodeEmitter::getMachineOpValue(const MCInst &MI,
113 const MCOperand &MO) const {
114 if (MO.isReg())
115 // FIXME: Should shifted register stuff be handled as part of this? Maybe.
116 return getARMRegisterNumbering(MO.getReg());
117 else if (MO.isImm())
118 // FIXME: This is insufficient. Shifted immediates and all that... (blech).
119 return static_cast<unsigned>(MO.getImm());
120 else {
121#ifndef NDEBUG
122 errs() << MO;
123#endif
124 llvm_unreachable(0);
125 }
126 return 0;
127}
128
Jim Grosbach568eeed2010-09-17 18:46:17 +0000129void ARMMCCodeEmitter::
130EncodeInstruction(const MCInst &MI, raw_ostream &OS,
131 SmallVectorImpl<MCFixup> &Fixups) const {
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000132 unsigned Opcode = MI.getOpcode();
133 const TargetInstrDesc &Desc = TII.get(Opcode);
134 uint64_t TSFlags = Desc.TSFlags;
Jim Grosbach58f38bf2010-10-08 00:39:21 +0000135 // Keep track of the current byte being emitted.
136 unsigned CurByte = 0;
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000137
138 // Pseudo instructions don't get encoded.
139 if ((TSFlags & ARMII::FormMask) == ARMII::Pseudo)
140 return;
141
142 ++MCNumEmitted; // Keep track of the # of mi's emitted
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000143 // FIXME: TableGen doesn't deal well with operands that expand to multiple
144 // machine instruction operands, so for now we'll fix those up here.
Jim Grosbach3e094132010-10-08 17:45:54 +0000145 switch (Opcode) {
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000146 case ARM::ADDrs:
147 case ARM::ANDrs:
148 case ARM::BICrs:
149 case ARM::EORrs:
150 case ARM::ORRrs:
151 case ARM::SUBrs: {
152 // The so_reg operand needs the shift ammount encoded.
153 unsigned Value = getBinaryCodeForInstr(MI);
154 unsigned ShVal = MI.getOperand(4).getImm();
155 unsigned ShType = ARM_AM::getShiftOpcEncoding(ARM_AM::getSORegShOp(ShVal));
156 unsigned ShAmt = ARM_AM::getSORegOffset(ShVal);
157
158 Value |= ShType << ARMII::ShiftTypeShift;
159 Value |= ShAmt << ARMII::ShiftShift;
160
161 EmitConstant(Value, 4, CurByte, OS);
162 break;
163 }
Jim Grosbach3e094132010-10-08 17:45:54 +0000164 default: {
Jim Grosbach58f38bf2010-10-08 00:39:21 +0000165 unsigned Value = getBinaryCodeForInstr(MI);
166 EmitConstant(Value, 4, CurByte, OS);
167 break;
168 }
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000169 }
Jim Grosbach568eeed2010-09-17 18:46:17 +0000170}
Jim Grosbach9af82ba2010-10-07 21:57:55 +0000171
172// FIXME: These #defines shouldn't be necessary. Instead, tblgen should
173// be able to generate code emitter helpers for either variant, like it
174// does for the AsmWriter.
175#define ARMCodeEmitter ARMMCCodeEmitter
176#define MachineInstr MCInst
177#include "ARMGenCodeEmitter.inc"
178#undef ARMCodeEmitter
179#undef MachineInstr