blob: 27ed5511134eb9dd4d69ae5f03ddc94bfdf95c91 [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 Grosbach0de6ab32010-10-12 17:11:26 +000042 unsigned getMachineSoImmOpValue(unsigned SoImm) const;
43
Jim Grosbach9af82ba2010-10-07 21:57:55 +000044 // getBinaryCodeForInstr - TableGen'erated function for getting the
45 // binary encoding for an instruction.
Jim Grosbachbade37b2010-10-08 00:21:28 +000046 unsigned getBinaryCodeForInstr(const MCInst &MI) const;
Jim Grosbach9af82ba2010-10-07 21:57:55 +000047
48 /// getMachineOpValue - Return binary encoding of operand. If the machine
49 /// operand requires relocation, record the relocation and return zero.
Jim Grosbach3e094132010-10-08 17:45:54 +000050 unsigned getMachineOpValue(const MCInst &MI,const MCOperand &MO) const;
51 unsigned getMachineOpValue(const MCInst &MI, unsigned OpIdx) const {
Jim Grosbach9af82ba2010-10-07 21:57:55 +000052 return getMachineOpValue(MI, MI.getOperand(OpIdx));
53 }
54
Jim Grosbach568eeed2010-09-17 18:46:17 +000055 unsigned getNumFixupKinds() const {
56 assert(0 && "ARMMCCodeEmitter::getNumFixupKinds() not yet implemented.");
Michael J. Spencer895dda62010-09-18 17:54:37 +000057 return 0;
Jim Grosbach568eeed2010-09-17 18:46:17 +000058 }
59
60 const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
61 static MCFixupKindInfo rtn;
62 assert(0 && "ARMMCCodeEmitter::getFixupKindInfo() not yet implemented.");
63 return rtn;
64 }
65
Jim Grosbach568eeed2010-09-17 18:46:17 +000066 void EmitByte(unsigned char C, unsigned &CurByte, raw_ostream &OS) const {
67 OS << (char)C;
68 ++CurByte;
69 }
70
71 void EmitConstant(uint64_t Val, unsigned Size, unsigned &CurByte,
72 raw_ostream &OS) const {
73 // Output the constant in little endian byte order.
74 for (unsigned i = 0; i != Size; ++i) {
75 EmitByte(Val & 255, CurByte, OS);
76 Val >>= 8;
77 }
78 }
79
80 void EmitImmediate(const MCOperand &Disp,
81 unsigned ImmSize, MCFixupKind FixupKind,
82 unsigned &CurByte, raw_ostream &OS,
83 SmallVectorImpl<MCFixup> &Fixups,
84 int ImmOffset = 0) const;
85
86 void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
87 SmallVectorImpl<MCFixup> &Fixups) const;
Jim Grosbach568eeed2010-09-17 18:46:17 +000088};
89
90} // end anonymous namespace
91
Jim Grosbach0de6ab32010-10-12 17:11:26 +000092unsigned ARMMCCodeEmitter::getMachineSoImmOpValue(unsigned SoImm) const {
93 int SoImmVal = ARM_AM::getSOImmVal(SoImm);
94 assert(SoImmVal != -1 && "Not a valid so_imm value!");
95
96 // Encode rotate_imm.
97 unsigned Binary = (ARM_AM::getSOImmValRot((unsigned)SoImmVal) >> 1)
98 << ARMII::SoRotImmShift;
99
100 // Encode immed_8.
101 Binary |= ARM_AM::getSOImmValImm((unsigned)SoImmVal);
102 return Binary;
103}
Jim Grosbach568eeed2010-09-17 18:46:17 +0000104
105MCCodeEmitter *llvm::createARMMCCodeEmitter(const Target &,
106 TargetMachine &TM,
107 MCContext &Ctx) {
108 return new ARMMCCodeEmitter(TM, Ctx);
109}
110
111void ARMMCCodeEmitter::
112EmitImmediate(const MCOperand &DispOp, unsigned Size, MCFixupKind FixupKind,
113 unsigned &CurByte, raw_ostream &OS,
114 SmallVectorImpl<MCFixup> &Fixups, int ImmOffset) const {
115 assert(0 && "ARMMCCodeEmitter::EmitImmediate() not yet implemented.");
116}
117
Jim Grosbach56ac9072010-10-08 21:45:55 +0000118/// getMachineOpValue - Return binary encoding of operand. If the machine
119/// operand requires relocation, record the relocation and return zero.
120unsigned ARMMCCodeEmitter::getMachineOpValue(const MCInst &MI,
121 const MCOperand &MO) const {
122 if (MO.isReg())
Jim Grosbach56ac9072010-10-08 21:45:55 +0000123 return getARMRegisterNumbering(MO.getReg());
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000124 else if (MO.isImm()) {
Jim Grosbach56ac9072010-10-08 21:45:55 +0000125 return static_cast<unsigned>(MO.getImm());
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000126 } else {
Jim Grosbach56ac9072010-10-08 21:45:55 +0000127#ifndef NDEBUG
128 errs() << MO;
129#endif
130 llvm_unreachable(0);
131 }
132 return 0;
133}
134
Jim Grosbach568eeed2010-09-17 18:46:17 +0000135void ARMMCCodeEmitter::
136EncodeInstruction(const MCInst &MI, raw_ostream &OS,
137 SmallVectorImpl<MCFixup> &Fixups) const {
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000138 unsigned Opcode = MI.getOpcode();
139 const TargetInstrDesc &Desc = TII.get(Opcode);
140 uint64_t TSFlags = Desc.TSFlags;
Jim Grosbach58f38bf2010-10-08 00:39:21 +0000141 // Keep track of the current byte being emitted.
142 unsigned CurByte = 0;
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000143
144 // Pseudo instructions don't get encoded.
145 if ((TSFlags & ARMII::FormMask) == ARMII::Pseudo)
146 return;
147
148 ++MCNumEmitted; // Keep track of the # of mi's emitted
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000149 // FIXME: TableGen doesn't deal well with operands that expand to multiple
150 // machine instruction operands, so for now we'll fix those up here.
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000151 // Similarly, operands that are encoded as other than their literal
152 // values in the MI.
153 unsigned Value = getBinaryCodeForInstr(MI);
Jim Grosbach3e094132010-10-08 17:45:54 +0000154 switch (Opcode) {
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000155 default: break;
156 case ARM::ADDri:
157 case ARM::ANDri:
158 case ARM::BICri:
159 case ARM::EORri:
160 case ARM::ORRri:
161 case ARM::SUBri:
162 // The 's' bit.
163 if (MI.getOperand(5).getReg() == ARM::CPSR)
164 Value |= 1 << ARMII::S_BitShift;
165 // The shifted immediate value.
166 Value |= getMachineSoImmOpValue((unsigned)MI.getOperand(2).getImm());
167 break;
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000168 case ARM::ADDrs:
169 case ARM::ANDrs:
170 case ARM::BICrs:
171 case ARM::EORrs:
172 case ARM::ORRrs:
173 case ARM::SUBrs: {
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000174 // The 's' bit.
175 if (MI.getOperand(7).getReg() == ARM::CPSR)
176 Value |= 1 << ARMII::S_BitShift;
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000177 // The so_reg operand needs the shift ammount encoded.
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000178 unsigned ShVal = MI.getOperand(4).getImm();
179 unsigned ShType = ARM_AM::getShiftOpcEncoding(ARM_AM::getSORegShOp(ShVal));
180 unsigned ShAmt = ARM_AM::getSORegOffset(ShVal);
Jim Grosbach42fac8e2010-10-11 23:16:21 +0000181 Value |= ShType << ARMII::ShiftTypeShift;
182 Value |= ShAmt << ARMII::ShiftShift;
Jim Grosbach58f38bf2010-10-08 00:39:21 +0000183 break;
184 }
Jim Grosbachd6d4b422010-10-07 22:12:50 +0000185 }
Jim Grosbach0de6ab32010-10-12 17:11:26 +0000186 EmitConstant(Value, 4, CurByte, OS);
Jim Grosbach568eeed2010-09-17 18:46:17 +0000187}
Jim Grosbach9af82ba2010-10-07 21:57:55 +0000188
189// FIXME: These #defines shouldn't be necessary. Instead, tblgen should
190// be able to generate code emitter helpers for either variant, like it
191// does for the AsmWriter.
192#define ARMCodeEmitter ARMMCCodeEmitter
193#define MachineInstr MCInst
194#include "ARMGenCodeEmitter.inc"
195#undef ARMCodeEmitter
196#undef MachineInstr