blob: 2ec1356ca56feb1c6c010463b8fc365026559c6a [file] [log] [blame]
Jan Voungb36ad9b2015-04-21 17:01:49 -07001//===- subzero/src/IceInstARM32.h - ARM32 machine instructions --*- C++ -*-===//
2//
3// The Subzero Code Generator
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 declares the InstARM32 and OperandARM32 classes and
11// their subclasses. This represents the machine instructions and
12// operands used for ARM32 code selection.
13//
14//===----------------------------------------------------------------------===//
15
16#ifndef SUBZERO_SRC_ICEINSTARM32_H
17#define SUBZERO_SRC_ICEINSTARM32_H
18
Jan Voung3bfd99a2015-05-22 16:35:25 -070019#include "IceConditionCodesARM32.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070020#include "IceDefs.h"
Jan Voungb2d50842015-05-12 09:53:50 -070021#include "IceInst.h"
22#include "IceInstARM32.def"
23#include "IceOperand.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070024
25namespace Ice {
26
27class TargetARM32;
Jan Voungb2d50842015-05-12 09:53:50 -070028
Jan Voungb3401d22015-05-18 09:38:21 -070029// OperandARM32 extends the Operand hierarchy. Its subclasses are
30// OperandARM32Mem and OperandARM32Flex.
Jan Voungb2d50842015-05-12 09:53:50 -070031class OperandARM32 : public Operand {
32 OperandARM32() = delete;
33 OperandARM32(const OperandARM32 &) = delete;
34 OperandARM32 &operator=(const OperandARM32 &) = delete;
35
36public:
Jan Voungb3401d22015-05-18 09:38:21 -070037 enum OperandKindARM32 {
38 k__Start = Operand::kTarget,
39 kMem,
40 kFlexStart,
41 kFlexImm = kFlexStart,
42 kFlexReg,
43 kFlexEnd = kFlexReg
44 };
Jan Voungb2d50842015-05-12 09:53:50 -070045
46 enum ShiftKind {
47 kNoShift = -1,
48#define X(enum, emit) enum,
49 ICEINSTARM32SHIFT_TABLE
50#undef X
51 };
52
53 using Operand::dump;
54 void dump(const Cfg *, Ostream &Str) const override {
55 if (ALLOW_DUMP)
56 Str << "<OperandARM32>";
57 }
58
59protected:
60 OperandARM32(OperandKindARM32 Kind, Type Ty)
61 : Operand(static_cast<OperandKind>(Kind), Ty) {}
Jan Voungb2d50842015-05-12 09:53:50 -070062};
63
64// OperandARM32Mem represents a memory operand in any of the various ARM32
65// addressing modes.
Jan Voungb2d50842015-05-12 09:53:50 -070066class OperandARM32Mem : public OperandARM32 {
67 OperandARM32Mem() = delete;
68 OperandARM32Mem(const OperandARM32Mem &) = delete;
69 OperandARM32Mem &operator=(const OperandARM32Mem &) = delete;
70
71public:
Jan Voungb3401d22015-05-18 09:38:21 -070072 // Memory operand addressing mode.
73 // The enum value also carries the encoding.
74 // TODO(jvoung): unify with the assembler.
75 enum AddrMode {
76 // bit encoding P U W
77 Offset = (8 | 4 | 0) << 21, // offset (w/o writeback to base)
78 PreIndex = (8 | 4 | 1) << 21, // pre-indexed addressing with writeback
79 PostIndex = (0 | 4 | 0) << 21, // post-indexed addressing with writeback
80 NegOffset = (8 | 0 | 0) << 21, // negative offset (w/o writeback to base)
81 NegPreIndex = (8 | 0 | 1) << 21, // negative pre-indexed with writeback
82 NegPostIndex = (0 | 0 | 0) << 21 // negative post-indexed with writeback
83 };
84
85 // Provide two constructors.
86 // NOTE: The Variable-typed operands have to be registers.
87 //
88 // (1) Reg + Imm. The Immediate actually has a limited number of bits
89 // for encoding, so check canHoldOffset first. It cannot handle
90 // general Constant operands like ConstantRelocatable, since a relocatable
91 // can potentially take up too many bits.
92 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base,
Jan Voungbefd03a2015-06-02 11:03:03 -070093 ConstantInteger32 *ImmOffset,
Jan Voungb3401d22015-05-18 09:38:21 -070094 AddrMode Mode = Offset) {
95 return new (Func->allocate<OperandARM32Mem>())
96 OperandARM32Mem(Func, Ty, Base, ImmOffset, Mode);
97 }
98 // (2) Reg +/- Reg with an optional shift of some kind and amount.
99 // Note that this mode is disallowed in the NaCl sandbox.
100 static OperandARM32Mem *create(Cfg *Func, Type Ty, Variable *Base,
101 Variable *Index, ShiftKind ShiftOp = kNoShift,
102 uint16_t ShiftAmt = 0,
103 AddrMode Mode = Offset) {
104 return new (Func->allocate<OperandARM32Mem>())
105 OperandARM32Mem(Func, Ty, Base, Index, ShiftOp, ShiftAmt, Mode);
106 }
107 Variable *getBase() const { return Base; }
108 ConstantInteger32 *getOffset() const { return ImmOffset; }
109 Variable *getIndex() const { return Index; }
110 ShiftKind getShiftOp() const { return ShiftOp; }
111 uint16_t getShiftAmt() const { return ShiftAmt; }
112 AddrMode getAddrMode() const { return Mode; }
113
114 bool isRegReg() const { return Index != nullptr; }
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700115 bool isNegAddrMode() const {
116 // Positive address modes have the "U" bit set, and negative modes don't.
117 static_assert((PreIndex & (4 << 21)) != 0,
118 "Positive addr modes should have U bit set.");
119 static_assert((NegPreIndex & (4 << 21)) == 0,
120 "Negative addr modes should have U bit clear.");
121 return (Mode & (4 << 21)) == 0;
122 }
Jan Voungb3401d22015-05-18 09:38:21 -0700123
124 void emit(const Cfg *Func) const override;
125 using OperandARM32::dump;
126 void dump(const Cfg *Func, Ostream &Str) const override;
127
128 static bool classof(const Operand *Operand) {
129 return Operand->getKind() == static_cast<OperandKind>(kMem);
130 }
131
Jan Voungb2d50842015-05-12 09:53:50 -0700132 // Return true if a load/store instruction for an element of type Ty
133 // can encode the Offset directly in the immediate field of the 32-bit
134 // ARM instruction. For some types, if the load is Sign extending, then
135 // the range is reduced.
136 static bool canHoldOffset(Type Ty, bool SignExt, int32_t Offset);
Jan Voungb3401d22015-05-18 09:38:21 -0700137
138private:
139 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base,
140 ConstantInteger32 *ImmOffset, AddrMode Mode);
141 OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base, Variable *Index,
142 ShiftKind ShiftOp, uint16_t ShiftAmt, AddrMode Mode);
John Porto1bec8bc2015-06-22 10:51:13 -0700143
Jan Voungb3401d22015-05-18 09:38:21 -0700144 Variable *Base;
145 ConstantInteger32 *ImmOffset;
146 Variable *Index;
147 ShiftKind ShiftOp;
148 uint16_t ShiftAmt;
149 AddrMode Mode;
150};
151
152// OperandARM32Flex represent the "flexible second operand" for
153// data-processing instructions. It can be a rotatable 8-bit constant, or
154// a register with an optional shift operand. The shift amount can even be
155// a third register.
156class OperandARM32Flex : public OperandARM32 {
157 OperandARM32Flex() = delete;
158 OperandARM32Flex(const OperandARM32Flex &) = delete;
159 OperandARM32Flex &operator=(const OperandARM32Flex &) = delete;
160
161public:
162 static bool classof(const Operand *Operand) {
163 return static_cast<OperandKind>(kFlexStart) <= Operand->getKind() &&
164 Operand->getKind() <= static_cast<OperandKind>(kFlexEnd);
165 }
166
167protected:
168 OperandARM32Flex(OperandKindARM32 Kind, Type Ty) : OperandARM32(Kind, Ty) {}
Jan Voungb3401d22015-05-18 09:38:21 -0700169};
170
171// Rotated immediate variant.
172class OperandARM32FlexImm : public OperandARM32Flex {
173 OperandARM32FlexImm() = delete;
174 OperandARM32FlexImm(const OperandARM32FlexImm &) = delete;
175 OperandARM32FlexImm &operator=(const OperandARM32FlexImm &) = delete;
176
177public:
178 // Immed_8 rotated by an even number of bits (2 * RotateAmt).
179 static OperandARM32FlexImm *create(Cfg *Func, Type Ty, uint32_t Imm,
180 uint32_t RotateAmt) {
181 return new (Func->allocate<OperandARM32FlexImm>())
182 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt);
183 }
184
185 void emit(const Cfg *Func) const override;
186 using OperandARM32::dump;
187 void dump(const Cfg *Func, Ostream &Str) const override;
188
189 static bool classof(const Operand *Operand) {
190 return Operand->getKind() == static_cast<OperandKind>(kFlexImm);
191 }
192
193 // Return true if the Immediate can fit in the ARM flexible operand.
194 // Fills in the out-params RotateAmt and Immed_8 if Immediate fits.
195 static bool canHoldImm(uint32_t Immediate, uint32_t *RotateAmt,
196 uint32_t *Immed_8);
197
198 uint32_t getImm() const { return Imm; }
199 uint32_t getRotateAmt() const { return RotateAmt; }
200
201private:
202 OperandARM32FlexImm(Cfg *Func, Type Ty, uint32_t Imm, uint32_t RotateAmt);
Jan Voungb3401d22015-05-18 09:38:21 -0700203
204 uint32_t Imm;
205 uint32_t RotateAmt;
206};
207
208// Shifted register variant.
209class OperandARM32FlexReg : public OperandARM32Flex {
210 OperandARM32FlexReg() = delete;
211 OperandARM32FlexReg(const OperandARM32FlexReg &) = delete;
212 OperandARM32FlexReg &operator=(const OperandARM32FlexReg &) = delete;
213
214public:
215 // Register with immediate/reg shift amount and shift operation.
216 static OperandARM32FlexReg *create(Cfg *Func, Type Ty, Variable *Reg,
217 ShiftKind ShiftOp, Operand *ShiftAmt) {
218 return new (Func->allocate<OperandARM32FlexReg>())
219 OperandARM32FlexReg(Func, Ty, Reg, ShiftOp, ShiftAmt);
220 }
221
222 void emit(const Cfg *Func) const override;
223 using OperandARM32::dump;
224 void dump(const Cfg *Func, Ostream &Str) const override;
225
226 static bool classof(const Operand *Operand) {
227 return Operand->getKind() == static_cast<OperandKind>(kFlexReg);
228 }
229
230 Variable *getReg() const { return Reg; }
231 ShiftKind getShiftOp() const { return ShiftOp; }
232 // ShiftAmt can represent an immediate or a register.
233 Operand *getShiftAmt() const { return ShiftAmt; }
234
235private:
236 OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg, ShiftKind ShiftOp,
237 Operand *ShiftAmt);
Jan Voungb3401d22015-05-18 09:38:21 -0700238
239 Variable *Reg;
240 ShiftKind ShiftOp;
241 Operand *ShiftAmt;
Jan Voungb2d50842015-05-12 09:53:50 -0700242};
243
Jan Voung3bfd99a2015-05-22 16:35:25 -0700244// Base class for ARM instructions. While most ARM instructions can be
245// conditionally executed, a few of them are not predicable (halt,
246// memory barriers, etc.).
Jan Voungb2d50842015-05-12 09:53:50 -0700247class InstARM32 : public InstTarget {
248 InstARM32() = delete;
249 InstARM32(const InstARM32 &) = delete;
250 InstARM32 &operator=(const InstARM32 &) = delete;
251
252public:
Jan Voungb3401d22015-05-18 09:38:21 -0700253 enum InstKindARM32 {
254 k__Start = Inst::Target,
Jan Voung29719972015-05-19 11:24:51 -0700255 Adc,
256 Add,
Jan Voungb0a8c242015-06-18 15:00:14 -0700257 Adjuststack,
Jan Voung29719972015-05-19 11:24:51 -0700258 And,
Jan Voung66c3d5e2015-06-04 17:02:31 -0700259 Asr,
Jan Voung55500db2015-05-26 14:25:40 -0700260 Bic,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700261 Br,
262 Call,
263 Cmp,
Jan Voung29719972015-05-19 11:24:51 -0700264 Eor,
265 Ldr,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700266 Lsl,
Jan Voung66c3d5e2015-06-04 17:02:31 -0700267 Lsr,
Jan Voung29719972015-05-19 11:24:51 -0700268 Mla,
Jan Voungb3401d22015-05-18 09:38:21 -0700269 Mov,
270 Movt,
271 Movw,
Jan Voung29719972015-05-19 11:24:51 -0700272 Mul,
Jan Voungb3401d22015-05-18 09:38:21 -0700273 Mvn,
Jan Voung29719972015-05-19 11:24:51 -0700274 Orr,
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700275 Pop,
276 Push,
Jan Voungb3401d22015-05-18 09:38:21 -0700277 Ret,
Jan Voung66c3d5e2015-06-04 17:02:31 -0700278 Rsb,
Jan Voung29719972015-05-19 11:24:51 -0700279 Sbc,
Jan Voungbefd03a2015-06-02 11:03:03 -0700280 Str,
Jan Voung29719972015-05-19 11:24:51 -0700281 Sub,
Jan Voung66c3d5e2015-06-04 17:02:31 -0700282 Sxt,
283 Umull,
284 Uxt
Jan Voungb3401d22015-05-18 09:38:21 -0700285 };
Jan Voungb2d50842015-05-12 09:53:50 -0700286
287 static const char *getWidthString(Type Ty);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700288 static CondARM32::Cond getOppositeCondition(CondARM32::Cond Cond);
Jan Voungb2d50842015-05-12 09:53:50 -0700289
290 void dump(const Cfg *Func) const override;
291
292protected:
293 InstARM32(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest)
294 : InstTarget(Func, static_cast<InstKind>(Kind), Maxsrcs, Dest) {}
John Porto1bec8bc2015-06-22 10:51:13 -0700295
Jan Voungb2d50842015-05-12 09:53:50 -0700296 static bool isClassof(const Inst *Inst, InstKindARM32 MyKind) {
297 return Inst->getKind() == static_cast<InstKind>(MyKind);
298 }
299};
300
Jan Voung3bfd99a2015-05-22 16:35:25 -0700301// A predicable ARM instruction.
302class InstARM32Pred : public InstARM32 {
303 InstARM32Pred() = delete;
304 InstARM32Pred(const InstARM32Pred &) = delete;
305 InstARM32Pred &operator=(const InstARM32Pred &) = delete;
Jan Voungb3401d22015-05-18 09:38:21 -0700306
Jan Voung3bfd99a2015-05-22 16:35:25 -0700307public:
308 InstARM32Pred(Cfg *Func, InstKindARM32 Kind, SizeT Maxsrcs, Variable *Dest,
309 CondARM32::Cond Predicate)
310 : InstARM32(Func, Kind, Maxsrcs, Dest), Predicate(Predicate) {}
311
312 CondARM32::Cond getPredicate() const { return Predicate; }
313 void setPredicate(CondARM32::Cond Pred) { Predicate = Pred; }
314
315 static const char *predString(CondARM32::Cond Predicate);
316 void dumpOpcodePred(Ostream &Str, const char *Opcode, Type Ty) const;
317
318 // Shared emit routines for common forms of instructions.
Jan Voung66c3d5e2015-06-04 17:02:31 -0700319 static void emitUnaryopGPR(const char *Opcode, const InstARM32Pred *Inst,
320 const Cfg *Func);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700321 static void emitTwoAddr(const char *Opcode, const InstARM32Pred *Inst,
322 const Cfg *Func);
323 static void emitThreeAddr(const char *Opcode, const InstARM32Pred *Inst,
324 const Cfg *Func, bool SetFlags);
325
326protected:
327 CondARM32::Cond Predicate;
328};
329
330template <typename StreamType>
331inline StreamType &operator<<(StreamType &Stream, CondARM32::Cond Predicate) {
332 Stream << InstARM32Pred::predString(Predicate);
333 return Stream;
334}
Jan Voungb3401d22015-05-18 09:38:21 -0700335
336// Instructions of the form x := op(y).
337template <InstARM32::InstKindARM32 K>
Jan Voung3bfd99a2015-05-22 16:35:25 -0700338class InstARM32UnaryopGPR : public InstARM32Pred {
Jan Voungb3401d22015-05-18 09:38:21 -0700339 InstARM32UnaryopGPR() = delete;
340 InstARM32UnaryopGPR(const InstARM32UnaryopGPR &) = delete;
341 InstARM32UnaryopGPR &operator=(const InstARM32UnaryopGPR &) = delete;
342
343public:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700344 static InstARM32UnaryopGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
345 CondARM32::Cond Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700346 return new (Func->allocate<InstARM32UnaryopGPR>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700347 InstARM32UnaryopGPR(Func, Dest, Src, Predicate);
Jan Voungb3401d22015-05-18 09:38:21 -0700348 }
349 void emit(const Cfg *Func) const override {
350 if (!ALLOW_DUMP)
351 return;
Jan Voung66c3d5e2015-06-04 17:02:31 -0700352 emitUnaryopGPR(Opcode, this, Func);
Jan Voungb3401d22015-05-18 09:38:21 -0700353 }
354 void emitIAS(const Cfg *Func) const override {
355 (void)Func;
356 llvm_unreachable("Not yet implemented");
357 }
358 void dump(const Cfg *Func) const override {
359 if (!ALLOW_DUMP)
360 return;
361 Ostream &Str = Func->getContext()->getStrDump();
362 dumpDest(Func);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700363 Str << " = ";
364 dumpOpcodePred(Str, Opcode, getDest()->getType());
365 Str << " ";
Jan Voungb3401d22015-05-18 09:38:21 -0700366 dumpSources(Func);
367 }
368 static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
369
370private:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700371 InstARM32UnaryopGPR(Cfg *Func, Variable *Dest, Operand *Src,
372 CondARM32::Cond Predicate)
373 : InstARM32Pred(Func, K, 1, Dest, Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700374 addSource(Src);
375 }
John Porto1bec8bc2015-06-22 10:51:13 -0700376
Jan Voungb3401d22015-05-18 09:38:21 -0700377 static const char *Opcode;
378};
379
380// Instructions of the form x := x op y.
381template <InstARM32::InstKindARM32 K>
Jan Voung3bfd99a2015-05-22 16:35:25 -0700382class InstARM32TwoAddrGPR : public InstARM32Pred {
Jan Voungb3401d22015-05-18 09:38:21 -0700383 InstARM32TwoAddrGPR() = delete;
384 InstARM32TwoAddrGPR(const InstARM32TwoAddrGPR &) = delete;
385 InstARM32TwoAddrGPR &operator=(const InstARM32TwoAddrGPR &) = delete;
386
387public:
388 // Dest must be a register.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700389 static InstARM32TwoAddrGPR *create(Cfg *Func, Variable *Dest, Operand *Src,
390 CondARM32::Cond Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700391 return new (Func->allocate<InstARM32TwoAddrGPR>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700392 InstARM32TwoAddrGPR(Func, Dest, Src, Predicate);
Jan Voungb3401d22015-05-18 09:38:21 -0700393 }
394 void emit(const Cfg *Func) const override {
395 if (!ALLOW_DUMP)
396 return;
397 emitTwoAddr(Opcode, this, Func);
398 }
399 void emitIAS(const Cfg *Func) const override {
400 (void)Func;
401 llvm::report_fatal_error("Not yet implemented");
402 }
403 void dump(const Cfg *Func) const override {
404 if (!ALLOW_DUMP)
405 return;
406 Ostream &Str = Func->getContext()->getStrDump();
407 dumpDest(Func);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700408 Str << " = ";
409 dumpOpcodePred(Str, Opcode, getDest()->getType());
410 Str << " ";
Jan Voungb3401d22015-05-18 09:38:21 -0700411 dumpSources(Func);
412 }
413 static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
414
415private:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700416 InstARM32TwoAddrGPR(Cfg *Func, Variable *Dest, Operand *Src,
417 CondARM32::Cond Predicate)
418 : InstARM32Pred(Func, K, 2, Dest, Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700419 addSource(Dest);
420 addSource(Src);
421 }
John Porto1bec8bc2015-06-22 10:51:13 -0700422
Jan Voungb3401d22015-05-18 09:38:21 -0700423 static const char *Opcode;
424};
425
426// Base class for assignment instructions.
427// These can be tested for redundancy (and elided if redundant).
428template <InstARM32::InstKindARM32 K>
Jan Voung3bfd99a2015-05-22 16:35:25 -0700429class InstARM32Movlike : public InstARM32Pred {
Jan Voungb3401d22015-05-18 09:38:21 -0700430 InstARM32Movlike() = delete;
431 InstARM32Movlike(const InstARM32Movlike &) = delete;
432 InstARM32Movlike &operator=(const InstARM32Movlike &) = delete;
433
434public:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700435 static InstARM32Movlike *create(Cfg *Func, Variable *Dest, Operand *Source,
436 CondARM32::Cond Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700437 return new (Func->allocate<InstARM32Movlike>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700438 InstARM32Movlike(Func, Dest, Source, Predicate);
Jan Voungb3401d22015-05-18 09:38:21 -0700439 }
440 bool isRedundantAssign() const override {
441 return checkForRedundantAssign(getDest(), getSrc(0));
442 }
443 bool isSimpleAssign() const override { return true; }
444 void emit(const Cfg *Func) const override;
445 void emitIAS(const Cfg *Func) const override;
446 void dump(const Cfg *Func) const override {
447 if (!ALLOW_DUMP)
448 return;
449 Ostream &Str = Func->getContext()->getStrDump();
Jan Voung3bfd99a2015-05-22 16:35:25 -0700450 dumpOpcodePred(Str, Opcode, getDest()->getType());
451 Str << " ";
Jan Voungb3401d22015-05-18 09:38:21 -0700452 dumpDest(Func);
453 Str << ", ";
454 dumpSources(Func);
455 }
456 static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
457
458private:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700459 InstARM32Movlike(Cfg *Func, Variable *Dest, Operand *Source,
460 CondARM32::Cond Predicate)
461 : InstARM32Pred(Func, K, 1, Dest, Predicate) {
Jan Voungb3401d22015-05-18 09:38:21 -0700462 addSource(Source);
463 }
Jan Voungb3401d22015-05-18 09:38:21 -0700464
465 static const char *Opcode;
466};
467
Jan Voung29719972015-05-19 11:24:51 -0700468// Instructions of the form x := y op z. May have the side-effect of setting
469// status flags.
470template <InstARM32::InstKindARM32 K>
Jan Voung3bfd99a2015-05-22 16:35:25 -0700471class InstARM32ThreeAddrGPR : public InstARM32Pred {
Jan Voung29719972015-05-19 11:24:51 -0700472 InstARM32ThreeAddrGPR() = delete;
473 InstARM32ThreeAddrGPR(const InstARM32ThreeAddrGPR &) = delete;
474 InstARM32ThreeAddrGPR &operator=(const InstARM32ThreeAddrGPR &) = delete;
475
476public:
477 // Create an ordinary binary-op instruction like add, and sub.
478 // Dest and Src1 must be registers.
479 static InstARM32ThreeAddrGPR *create(Cfg *Func, Variable *Dest,
480 Variable *Src1, Operand *Src2,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700481 CondARM32::Cond Predicate,
Jan Voung29719972015-05-19 11:24:51 -0700482 bool SetFlags = false) {
483 return new (Func->allocate<InstARM32ThreeAddrGPR>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700484 InstARM32ThreeAddrGPR(Func, Dest, Src1, Src2, Predicate, SetFlags);
Jan Voung29719972015-05-19 11:24:51 -0700485 }
486 void emit(const Cfg *Func) const override {
487 if (!ALLOW_DUMP)
488 return;
489 emitThreeAddr(Opcode, this, Func, SetFlags);
490 }
491 void emitIAS(const Cfg *Func) const override {
492 (void)Func;
493 llvm::report_fatal_error("Not yet implemented");
494 }
495 void dump(const Cfg *Func) const override {
496 if (!ALLOW_DUMP)
497 return;
498 Ostream &Str = Func->getContext()->getStrDump();
499 dumpDest(Func);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700500 Str << " = ";
501 dumpOpcodePred(Str, Opcode, getDest()->getType());
502 Str << (SetFlags ? ".s " : " ");
Jan Voung29719972015-05-19 11:24:51 -0700503 dumpSources(Func);
504 }
505 static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
506
507private:
508 InstARM32ThreeAddrGPR(Cfg *Func, Variable *Dest, Variable *Src1,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700509 Operand *Src2, CondARM32::Cond Predicate, bool SetFlags)
510 : InstARM32Pred(Func, K, 2, Dest, Predicate), SetFlags(SetFlags) {
Jan Voung29719972015-05-19 11:24:51 -0700511 addSource(Src1);
512 addSource(Src2);
513 }
John Porto1bec8bc2015-06-22 10:51:13 -0700514
Jan Voung29719972015-05-19 11:24:51 -0700515 static const char *Opcode;
516 bool SetFlags;
517};
518
519typedef InstARM32ThreeAddrGPR<InstARM32::Adc> InstARM32Adc;
520typedef InstARM32ThreeAddrGPR<InstARM32::Add> InstARM32Add;
521typedef InstARM32ThreeAddrGPR<InstARM32::And> InstARM32And;
Jan Voung66c3d5e2015-06-04 17:02:31 -0700522typedef InstARM32ThreeAddrGPR<InstARM32::Asr> InstARM32Asr;
Jan Voung55500db2015-05-26 14:25:40 -0700523typedef InstARM32ThreeAddrGPR<InstARM32::Bic> InstARM32Bic;
Jan Voung29719972015-05-19 11:24:51 -0700524typedef InstARM32ThreeAddrGPR<InstARM32::Eor> InstARM32Eor;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700525typedef InstARM32ThreeAddrGPR<InstARM32::Lsl> InstARM32Lsl;
Jan Voung66c3d5e2015-06-04 17:02:31 -0700526typedef InstARM32ThreeAddrGPR<InstARM32::Lsr> InstARM32Lsr;
Jan Voung29719972015-05-19 11:24:51 -0700527typedef InstARM32ThreeAddrGPR<InstARM32::Mul> InstARM32Mul;
528typedef InstARM32ThreeAddrGPR<InstARM32::Orr> InstARM32Orr;
Jan Voung66c3d5e2015-06-04 17:02:31 -0700529typedef InstARM32ThreeAddrGPR<InstARM32::Rsb> InstARM32Rsb;
Jan Voung29719972015-05-19 11:24:51 -0700530typedef InstARM32ThreeAddrGPR<InstARM32::Sbc> InstARM32Sbc;
531typedef InstARM32ThreeAddrGPR<InstARM32::Sub> InstARM32Sub;
Jan Voungb3401d22015-05-18 09:38:21 -0700532// Move instruction (variable <- flex). This is more of a pseudo-inst.
533// If var is a register, then we use "mov". If var is stack, then we use
534// "str" to store to the stack.
535typedef InstARM32Movlike<InstARM32::Mov> InstARM32Mov;
536// MovT leaves the bottom bits alone so dest is also a source.
537// This helps indicate that a previous MovW setting dest is not dead code.
538typedef InstARM32TwoAddrGPR<InstARM32::Movt> InstARM32Movt;
539typedef InstARM32UnaryopGPR<InstARM32::Movw> InstARM32Movw;
540typedef InstARM32UnaryopGPR<InstARM32::Mvn> InstARM32Mvn;
Jan Voung66c3d5e2015-06-04 17:02:31 -0700541// Technically, the uxt{b,h} and sxt{b,h} instructions have a rotation
542// operand as well (rotate source by 8, 16, 24 bits prior to extending),
543// but we aren't using that for now, so just model as a Unaryop.
544typedef InstARM32UnaryopGPR<InstARM32::Sxt> InstARM32Sxt;
545typedef InstARM32UnaryopGPR<InstARM32::Uxt> InstARM32Uxt;
Jan Voungb3401d22015-05-18 09:38:21 -0700546
Jan Voung3bfd99a2015-05-22 16:35:25 -0700547// Direct branch instruction.
548class InstARM32Br : public InstARM32Pred {
549 InstARM32Br() = delete;
550 InstARM32Br(const InstARM32Br &) = delete;
551 InstARM32Br &operator=(const InstARM32Br &) = delete;
552
553public:
554 // Create a conditional branch to one of two nodes.
555 static InstARM32Br *create(Cfg *Func, CfgNode *TargetTrue,
556 CfgNode *TargetFalse, CondARM32::Cond Predicate) {
557 assert(Predicate != CondARM32::AL);
558 return new (Func->allocate<InstARM32Br>())
559 InstARM32Br(Func, TargetTrue, TargetFalse, Predicate);
560 }
561 // Create an unconditional branch to a node.
562 static InstARM32Br *create(Cfg *Func, CfgNode *Target) {
563 const CfgNode *NoCondTarget = nullptr;
564 return new (Func->allocate<InstARM32Br>())
565 InstARM32Br(Func, NoCondTarget, Target, CondARM32::AL);
566 }
567 // Create a non-terminator conditional branch to a node, with a
568 // fallthrough to the next instruction in the current node. This is
569 // used for switch lowering.
570 static InstARM32Br *create(Cfg *Func, CfgNode *Target,
571 CondARM32::Cond Predicate) {
572 assert(Predicate != CondARM32::AL);
573 const CfgNode *NoUncondTarget = nullptr;
574 return new (Func->allocate<InstARM32Br>())
575 InstARM32Br(Func, Target, NoUncondTarget, Predicate);
576 }
577 const CfgNode *getTargetTrue() const { return TargetTrue; }
578 const CfgNode *getTargetFalse() const { return TargetFalse; }
579 bool optimizeBranch(const CfgNode *NextNode);
580 uint32_t getEmitInstCount() const override {
581 uint32_t Sum = 0;
582 if (getTargetTrue())
583 ++Sum;
584 if (getTargetFalse())
585 ++Sum;
586 return Sum;
587 }
588 bool isUnconditionalBranch() const override {
589 return getPredicate() == CondARM32::AL;
590 }
591 bool repointEdge(CfgNode *OldNode, CfgNode *NewNode) override;
592 void emit(const Cfg *Func) const override;
593 void emitIAS(const Cfg *Func) const override;
594 void dump(const Cfg *Func) const override;
595 static bool classof(const Inst *Inst) { return isClassof(Inst, Br); }
596
597private:
598 InstARM32Br(Cfg *Func, const CfgNode *TargetTrue, const CfgNode *TargetFalse,
599 CondARM32::Cond Predicate);
John Porto1bec8bc2015-06-22 10:51:13 -0700600
Jan Voung3bfd99a2015-05-22 16:35:25 -0700601 const CfgNode *TargetTrue;
602 const CfgNode *TargetFalse;
603};
604
Jan Voungb0a8c242015-06-18 15:00:14 -0700605// AdjustStack instruction - subtracts SP by the given amount and
606// updates the stack offset during code emission.
607class InstARM32AdjustStack : public InstARM32 {
608 InstARM32AdjustStack() = delete;
609 InstARM32AdjustStack(const InstARM32AdjustStack &) = delete;
610 InstARM32AdjustStack &operator=(const InstARM32AdjustStack &) = delete;
611
612public:
613 // Note: We need both Amount and SrcAmount. If Amount is too large then
614 // it needs to be copied to a register (so SrcAmount could be a register).
615 // However, we also need the numeric Amount for bookkeeping, and it's
616 // hard to pull that from the generic SrcAmount operand.
617 static InstARM32AdjustStack *create(Cfg *Func, Variable *SP, SizeT Amount,
618 Operand *SrcAmount) {
619 return new (Func->allocate<InstARM32AdjustStack>())
620 InstARM32AdjustStack(Func, SP, Amount, SrcAmount);
621 }
622 void emit(const Cfg *Func) const override;
623 void emitIAS(const Cfg *Func) const override;
624 void dump(const Cfg *Func) const override;
625 static bool classof(const Inst *Inst) { return isClassof(Inst, Adjuststack); }
626
627private:
628 InstARM32AdjustStack(Cfg *Func, Variable *SP, SizeT Amount,
629 Operand *SrcAmount);
630 const SizeT Amount;
631};
632
Jan Voung3bfd99a2015-05-22 16:35:25 -0700633// Call instruction (bl/blx). Arguments should have already been pushed.
634// Technically bl and the register form of blx can be predicated, but we'll
635// leave that out until needed.
636class InstARM32Call : public InstARM32 {
637 InstARM32Call() = delete;
638 InstARM32Call(const InstARM32Call &) = delete;
639 InstARM32Call &operator=(const InstARM32Call &) = delete;
640
641public:
642 static InstARM32Call *create(Cfg *Func, Variable *Dest, Operand *CallTarget) {
643 return new (Func->allocate<InstARM32Call>())
644 InstARM32Call(Func, Dest, CallTarget);
645 }
646 Operand *getCallTarget() const { return getSrc(0); }
647 void emit(const Cfg *Func) const override;
648 void emitIAS(const Cfg *Func) const override;
649 void dump(const Cfg *Func) const override;
650 static bool classof(const Inst *Inst) { return isClassof(Inst, Call); }
651
652private:
653 InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700654};
655
656// Integer compare instruction.
657class InstARM32Cmp : public InstARM32Pred {
658 InstARM32Cmp() = delete;
659 InstARM32Cmp(const InstARM32Cmp &) = delete;
660 InstARM32Cmp &operator=(const InstARM32Cmp &) = delete;
661
662public:
663 static InstARM32Cmp *create(Cfg *Func, Variable *Src1, Operand *Src2,
664 CondARM32::Cond Predicate) {
665 return new (Func->allocate<InstARM32Cmp>())
666 InstARM32Cmp(Func, Src1, Src2, Predicate);
667 }
668 void emit(const Cfg *Func) const override;
669 void emitIAS(const Cfg *Func) const override;
670 void dump(const Cfg *Func) const override;
671 static bool classof(const Inst *Inst) { return isClassof(Inst, Cmp); }
672
673private:
674 InstARM32Cmp(Cfg *Func, Variable *Src1, Operand *Src2,
675 CondARM32::Cond Predicate);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700676};
677
Jan Voungb3401d22015-05-18 09:38:21 -0700678// Load instruction.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700679class InstARM32Ldr : public InstARM32Pred {
Jan Voungb3401d22015-05-18 09:38:21 -0700680 InstARM32Ldr() = delete;
681 InstARM32Ldr(const InstARM32Ldr &) = delete;
682 InstARM32Ldr &operator=(const InstARM32Ldr &) = delete;
683
684public:
685 // Dest must be a register.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700686 static InstARM32Ldr *create(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem,
687 CondARM32::Cond Predicate) {
688 return new (Func->allocate<InstARM32Ldr>())
689 InstARM32Ldr(Func, Dest, Mem, Predicate);
Jan Voungb3401d22015-05-18 09:38:21 -0700690 }
691 void emit(const Cfg *Func) const override;
692 void emitIAS(const Cfg *Func) const override;
693 void dump(const Cfg *Func) const override;
694 static bool classof(const Inst *Inst) { return isClassof(Inst, Ldr); }
695
696private:
Jan Voung3bfd99a2015-05-22 16:35:25 -0700697 InstARM32Ldr(Cfg *Func, Variable *Dest, OperandARM32Mem *Mem,
698 CondARM32::Cond Predicate);
Jan Voungb3401d22015-05-18 09:38:21 -0700699};
700
Jan Voung29719972015-05-19 11:24:51 -0700701// Multiply Accumulate: d := x * y + a
Jan Voung3bfd99a2015-05-22 16:35:25 -0700702class InstARM32Mla : public InstARM32Pred {
Jan Voung29719972015-05-19 11:24:51 -0700703 InstARM32Mla() = delete;
704 InstARM32Mla(const InstARM32Mla &) = delete;
705 InstARM32Mla &operator=(const InstARM32Mla &) = delete;
706
707public:
708 // Everything must be a register.
709 static InstARM32Mla *create(Cfg *Func, Variable *Dest, Variable *Src0,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700710 Variable *Src1, Variable *Acc,
711 CondARM32::Cond Predicate) {
Jan Voung29719972015-05-19 11:24:51 -0700712 return new (Func->allocate<InstARM32Mla>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700713 InstARM32Mla(Func, Dest, Src0, Src1, Acc, Predicate);
Jan Voung29719972015-05-19 11:24:51 -0700714 }
715 void emit(const Cfg *Func) const override;
716 void emitIAS(const Cfg *Func) const override;
717 void dump(const Cfg *Func) const override;
718 static bool classof(const Inst *Inst) { return isClassof(Inst, Mla); }
719
720private:
721 InstARM32Mla(Cfg *Func, Variable *Dest, Variable *Src0, Variable *Src1,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700722 Variable *Acc, CondARM32::Cond Predicate);
Jan Voung29719972015-05-19 11:24:51 -0700723};
724
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700725// Pop into a list of GPRs. Technically this can be predicated, but we don't
726// need that functionality.
727class InstARM32Pop : public InstARM32 {
728 InstARM32Pop() = delete;
729 InstARM32Pop(const InstARM32Pop &) = delete;
730 InstARM32Pop &operator=(const InstARM32Pop &) = delete;
731
732public:
733 static InstARM32Pop *create(Cfg *Func, const VarList &Dests) {
734 return new (Func->allocate<InstARM32Pop>()) InstARM32Pop(Func, Dests);
735 }
736 void emit(const Cfg *Func) const override;
737 void emitIAS(const Cfg *Func) const override;
738 void dump(const Cfg *Func) const override;
739 static bool classof(const Inst *Inst) { return isClassof(Inst, Pop); }
740
741private:
742 InstARM32Pop(Cfg *Func, const VarList &Dests);
John Porto1bec8bc2015-06-22 10:51:13 -0700743
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700744 VarList Dests;
745};
746
747// Push a list of GPRs. Technically this can be predicated, but we don't
748// need that functionality.
749class InstARM32Push : public InstARM32 {
750 InstARM32Push() = delete;
751 InstARM32Push(const InstARM32Push &) = delete;
752 InstARM32Push &operator=(const InstARM32Push &) = delete;
753
754public:
755 static InstARM32Push *create(Cfg *Func, const VarList &Srcs) {
756 return new (Func->allocate<InstARM32Push>()) InstARM32Push(Func, Srcs);
757 }
758 void emit(const Cfg *Func) const override;
759 void emitIAS(const Cfg *Func) const override;
760 void dump(const Cfg *Func) const override;
761 static bool classof(const Inst *Inst) { return isClassof(Inst, Push); }
762
763private:
764 InstARM32Push(Cfg *Func, const VarList &Srcs);
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700765};
766
Jan Voungb2d50842015-05-12 09:53:50 -0700767// Ret pseudo-instruction. This is actually a "bx" instruction with
768// an "lr" register operand, but epilogue lowering will search for a Ret
769// instead of a generic "bx". This instruction also takes a Source
770// operand (for non-void returning functions) for liveness analysis, though
771// a FakeUse before the ret would do just as well.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700772//
773// NOTE: Even though "bx" can be predicated, for now leave out the predication
774// since it's not yet known to be useful for Ret. That may complicate finding
775// the terminator instruction if it's not guaranteed to be executed.
Jan Voungb2d50842015-05-12 09:53:50 -0700776class InstARM32Ret : public InstARM32 {
777 InstARM32Ret() = delete;
778 InstARM32Ret(const InstARM32Ret &) = delete;
779 InstARM32Ret &operator=(const InstARM32Ret &) = delete;
780
781public:
782 static InstARM32Ret *create(Cfg *Func, Variable *LR,
783 Variable *Source = nullptr) {
784 return new (Func->allocate<InstARM32Ret>()) InstARM32Ret(Func, LR, Source);
785 }
786 void emit(const Cfg *Func) const override;
787 void emitIAS(const Cfg *Func) const override;
788 void dump(const Cfg *Func) const override;
789 static bool classof(const Inst *Inst) { return isClassof(Inst, Ret); }
790
791private:
792 InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source);
Jan Voungb2d50842015-05-12 09:53:50 -0700793};
Jan Voungb36ad9b2015-04-21 17:01:49 -0700794
Jan Voungbefd03a2015-06-02 11:03:03 -0700795// Store instruction. It's important for liveness that there is no Dest
796// operand (OperandARM32Mem instead of Dest Variable).
797class InstARM32Str : public InstARM32Pred {
798 InstARM32Str() = delete;
799 InstARM32Str(const InstARM32Str &) = delete;
800 InstARM32Str &operator=(const InstARM32Str &) = delete;
801
802public:
803 // Value must be a register.
804 static InstARM32Str *create(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
805 CondARM32::Cond Predicate) {
806 return new (Func->allocate<InstARM32Str>())
807 InstARM32Str(Func, Value, Mem, Predicate);
808 }
809 void emit(const Cfg *Func) const override;
810 void emitIAS(const Cfg *Func) const override;
811 void dump(const Cfg *Func) const override;
812 static bool classof(const Inst *Inst) { return isClassof(Inst, Str); }
813
814private:
815 InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
816 CondARM32::Cond Predicate);
Jan Voungbefd03a2015-06-02 11:03:03 -0700817};
818
Jan Voung29719972015-05-19 11:24:51 -0700819// Unsigned Multiply Long: d.lo, d.hi := x * y
Jan Voung3bfd99a2015-05-22 16:35:25 -0700820class InstARM32Umull : public InstARM32Pred {
Jan Voung29719972015-05-19 11:24:51 -0700821 InstARM32Umull() = delete;
822 InstARM32Umull(const InstARM32Umull &) = delete;
823 InstARM32Umull &operator=(const InstARM32Umull &) = delete;
824
825public:
826 // Everything must be a register.
827 static InstARM32Umull *create(Cfg *Func, Variable *DestLo, Variable *DestHi,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700828 Variable *Src0, Variable *Src1,
829 CondARM32::Cond Predicate) {
Jan Voung29719972015-05-19 11:24:51 -0700830 return new (Func->allocate<InstARM32Umull>())
Jan Voung3bfd99a2015-05-22 16:35:25 -0700831 InstARM32Umull(Func, DestLo, DestHi, Src0, Src1, Predicate);
Jan Voung29719972015-05-19 11:24:51 -0700832 }
833 void emit(const Cfg *Func) const override;
834 void emitIAS(const Cfg *Func) const override;
835 void dump(const Cfg *Func) const override;
836 static bool classof(const Inst *Inst) { return isClassof(Inst, Umull); }
837
838private:
839 InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi, Variable *Src0,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700840 Variable *Src1, CondARM32::Cond Predicate);
John Porto1bec8bc2015-06-22 10:51:13 -0700841
Jan Voung29719972015-05-19 11:24:51 -0700842 Variable *DestHi;
843};
844
Jan Voungb3401d22015-05-18 09:38:21 -0700845// Declare partial template specializations of emit() methods that
846// already have default implementations. Without this, there is the
847// possibility of ODR violations and link errors.
848
849template <> void InstARM32Movw::emit(const Cfg *Func) const;
850template <> void InstARM32Movt::emit(const Cfg *Func) const;
851
Jan Voungb36ad9b2015-04-21 17:01:49 -0700852} // end of namespace Ice
853
854#endif // SUBZERO_SRC_ICEINSTARM32_H