blob: fdb025f883bea6185eb82844e9565b0356e5f5d7 [file] [log] [blame]
Jan Voungb36ad9b2015-04-21 17:01:49 -07001//===- subzero/src/IceTargetLoweringARM32.h - ARM32 lowering ----*- 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 TargetLoweringARM32 class, which implements the
11// TargetLowering interface for the ARM 32-bit architecture.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef SUBZERO_SRC_ICETARGETLOWERINGARM32_H
16#define SUBZERO_SRC_ICETARGETLOWERINGARM32_H
17
18#include "IceDefs.h"
Jan Voungb2d50842015-05-12 09:53:50 -070019#include "IceInstARM32.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070020#include "IceRegistersARM32.h"
21#include "IceTargetLowering.h"
22
23namespace Ice {
24
25class TargetARM32 : public TargetLowering {
26 TargetARM32() = delete;
27 TargetARM32(const TargetARM32 &) = delete;
28 TargetARM32 &operator=(const TargetARM32 &) = delete;
29
30public:
31 // TODO(jvoung): return a unique_ptr.
32 static TargetARM32 *create(Cfg *Func) { return new TargetARM32(Func); }
33
34 void translateOm1() override;
35 void translateO2() override;
36 bool doBranchOpt(Inst *I, const CfgNode *NextNode) override;
37
38 SizeT getNumRegisters() const override { return RegARM32::Reg_NUM; }
39 Variable *getPhysicalRegister(SizeT RegNum, Type Ty = IceType_void) override;
40 IceString getRegName(SizeT RegNum, Type Ty) const override;
41 llvm::SmallBitVector getRegisterSet(RegSetMask Include,
42 RegSetMask Exclude) const override;
43 const llvm::SmallBitVector &getRegisterSetForType(Type Ty) const override {
44 return TypeToRegisterSet[Ty];
45 }
46 bool hasFramePointer() const override { return UsesFramePointer; }
47 SizeT getFrameOrStackReg() const override {
48 return UsesFramePointer ? RegARM32::Reg_fp : RegARM32::Reg_sp;
49 }
50 size_t typeWidthInBytesOnStack(Type Ty) const override {
51 // Round up to the next multiple of 4 bytes. In particular, i1,
52 // i8, and i16 are rounded up to 4 bytes.
53 return (typeWidthInBytes(Ty) + 3) & ~3;
54 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -070055
Jan Voungb36ad9b2015-04-21 17:01:49 -070056 void emitVariable(const Variable *Var) const override;
Jan Voung76bb0be2015-05-14 09:26:19 -070057
58 const char *getConstantPrefix() const final { return "#"; }
59 void emit(const ConstantUndef *C) const final;
60 void emit(const ConstantInteger32 *C) const final;
61 void emit(const ConstantInteger64 *C) const final;
62 void emit(const ConstantFloat *C) const final;
63 void emit(const ConstantDouble *C) const final;
64
Jan Voungb36ad9b2015-04-21 17:01:49 -070065 void lowerArguments() override;
66 void addProlog(CfgNode *Node) override;
67 void addEpilog(CfgNode *Node) override;
68
Jan Voungb3401d22015-05-18 09:38:21 -070069 // Ensure that a 64-bit Variable has been split into 2 32-bit
70 // Variables, creating them if necessary. This is needed for all
71 // I64 operations.
72 void split64(Variable *Var);
73 Operand *loOperand(Operand *Operand);
74 Operand *hiOperand(Operand *Operand);
Jan Voung0fa6c5a2015-06-01 11:04:04 -070075 void finishArgumentLowering(Variable *Arg, Variable *FramePtr,
76 size_t BasicFrameOffset, size_t &InArgsSizeBytes);
Jan Voungb3401d22015-05-18 09:38:21 -070077
Jan Voungd062f732015-06-15 17:17:31 -070078 enum ARM32InstructionSet {
79 Begin,
80 // Neon is the PNaCl baseline instruction set.
81 Neon = Begin,
82 HWDivArm, // HW divide in ARM mode (not just Thumb mode).
83 End
84 };
85
86 ARM32InstructionSet getInstructionSet() const { return InstructionSet; }
87
Jan Voungb36ad9b2015-04-21 17:01:49 -070088protected:
89 explicit TargetARM32(Cfg *Func);
90
91 void postLower() override;
92
93 void lowerAlloca(const InstAlloca *Inst) override;
94 void lowerArithmetic(const InstArithmetic *Inst) override;
95 void lowerAssign(const InstAssign *Inst) override;
96 void lowerBr(const InstBr *Inst) override;
97 void lowerCall(const InstCall *Inst) override;
98 void lowerCast(const InstCast *Inst) override;
99 void lowerExtractElement(const InstExtractElement *Inst) override;
100 void lowerFcmp(const InstFcmp *Inst) override;
101 void lowerIcmp(const InstIcmp *Inst) override;
102 void lowerIntrinsicCall(const InstIntrinsicCall *Inst) override;
103 void lowerInsertElement(const InstInsertElement *Inst) override;
104 void lowerLoad(const InstLoad *Inst) override;
105 void lowerPhi(const InstPhi *Inst) override;
106 void lowerRet(const InstRet *Inst) override;
107 void lowerSelect(const InstSelect *Inst) override;
108 void lowerStore(const InstStore *Inst) override;
109 void lowerSwitch(const InstSwitch *Inst) override;
110 void lowerUnreachable(const InstUnreachable *Inst) override;
111 void prelowerPhis() override;
112 void lowerPhiAssignments(CfgNode *Node,
113 const AssignList &Assignments) override;
114 void doAddressOptLoad() override;
115 void doAddressOptStore() override;
116 void randomlyInsertNop(float Probability) override;
Jan Voungb3401d22015-05-18 09:38:21 -0700117
118 enum OperandLegalization {
119 Legal_None = 0,
120 Legal_Reg = 1 << 0, // physical register, not stack location
121 Legal_Flex = 1 << 1, // A flexible operand2, which can hold rotated
122 // small immediates, or shifted registers.
123 Legal_Mem = 1 << 2, // includes [r0, r1 lsl #2] as well as [sp, #12]
124 Legal_All = ~Legal_None
125 };
126 typedef uint32_t LegalMask;
127 Operand *legalize(Operand *From, LegalMask Allowed = Legal_All,
128 int32_t RegNum = Variable::NoRegister);
129 Variable *legalizeToVar(Operand *From, int32_t RegNum = Variable::NoRegister);
Jan Voungbefd03a2015-06-02 11:03:03 -0700130 OperandARM32Mem *formMemoryOperand(Operand *Ptr, Type Ty);
Jan Voungb3401d22015-05-18 09:38:21 -0700131
132 Variable *makeReg(Type Ty, int32_t RegNum = Variable::NoRegister);
133 static Type stackSlotType();
134 Variable *copyToReg(Operand *Src, int32_t RegNum = Variable::NoRegister);
Jan Voung55500db2015-05-26 14:25:40 -0700135 void alignRegisterPow2(Variable *Reg, uint32_t Align);
Jan Voungb3401d22015-05-18 09:38:21 -0700136
137 // Returns a vector in a register with the given constant entries.
138 Variable *makeVectorOfZeros(Type Ty, int32_t RegNum = Variable::NoRegister);
139
Jan Voungb36ad9b2015-04-21 17:01:49 -0700140 void makeRandomRegisterPermutation(
141 llvm::SmallVectorImpl<int32_t> &Permutation,
142 const llvm::SmallBitVector &ExcludeRegisters) const override;
143
Jan Voungb2d50842015-05-12 09:53:50 -0700144 // The following are helpers that insert lowered ARM32 instructions
145 // with minimal syntactic overhead, so that the lowering code can
146 // look as close to assembly as practical.
147
Jan Voung3bfd99a2015-05-22 16:35:25 -0700148 void _add(Variable *Dest, Variable *Src0, Operand *Src1,
149 CondARM32::Cond Pred = CondARM32::AL) {
150 Context.insert(InstARM32Add::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700151 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700152 void _adds(Variable *Dest, Variable *Src0, Operand *Src1,
153 CondARM32::Cond Pred = CondARM32::AL) {
Jan Voung29719972015-05-19 11:24:51 -0700154 const bool SetFlags = true;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700155 Context.insert(
156 InstARM32Add::create(Func, Dest, Src0, Src1, Pred, SetFlags));
Jan Voung29719972015-05-19 11:24:51 -0700157 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700158 void _adc(Variable *Dest, Variable *Src0, Operand *Src1,
159 CondARM32::Cond Pred = CondARM32::AL) {
160 Context.insert(InstARM32Adc::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700161 }
Jan Voungb0a8c242015-06-18 15:00:14 -0700162 void _adjust_stack(int32_t Amount, Operand *SrcAmount) {
163 Context.insert(InstARM32AdjustStack::create(
164 Func, getPhysicalRegister(RegARM32::Reg_sp), Amount, SrcAmount));
165 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700166 void _and(Variable *Dest, Variable *Src0, Operand *Src1,
167 CondARM32::Cond Pred = CondARM32::AL) {
168 Context.insert(InstARM32And::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700169 }
Jan Voung66c3d5e2015-06-04 17:02:31 -0700170 void _asr(Variable *Dest, Variable *Src0, Operand *Src1,
171 CondARM32::Cond Pred = CondARM32::AL) {
172 Context.insert(InstARM32Asr::create(Func, Dest, Src0, Src1, Pred));
173 }
Jan Voung55500db2015-05-26 14:25:40 -0700174 void _bic(Variable *Dest, Variable *Src0, Operand *Src1,
175 CondARM32::Cond Pred = CondARM32::AL) {
176 Context.insert(InstARM32Bic::create(Func, Dest, Src0, Src1, Pred));
177 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700178 void _br(CondARM32::Cond Condition, CfgNode *TargetTrue,
179 CfgNode *TargetFalse) {
180 Context.insert(
181 InstARM32Br::create(Func, TargetTrue, TargetFalse, Condition));
Jan Voung29719972015-05-19 11:24:51 -0700182 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700183 void _br(CfgNode *Target) {
184 Context.insert(InstARM32Br::create(Func, Target));
Jan Voungb3401d22015-05-18 09:38:21 -0700185 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700186 void _cmp(Variable *Src0, Operand *Src1,
187 CondARM32::Cond Pred = CondARM32::AL) {
188 Context.insert(InstARM32Cmp::create(Func, Src0, Src1, Pred));
189 }
190 void _eor(Variable *Dest, Variable *Src0, Operand *Src1,
191 CondARM32::Cond Pred = CondARM32::AL) {
192 Context.insert(InstARM32Eor::create(Func, Dest, Src0, Src1, Pred));
193 }
194 void _ldr(Variable *Dest, OperandARM32Mem *Addr,
195 CondARM32::Cond Pred = CondARM32::AL) {
196 Context.insert(InstARM32Ldr::create(Func, Dest, Addr, Pred));
197 }
198 void _lsl(Variable *Dest, Variable *Src0, Operand *Src1,
199 CondARM32::Cond Pred = CondARM32::AL) {
200 Context.insert(InstARM32Lsl::create(Func, Dest, Src0, Src1, Pred));
201 }
Jan Voung66c3d5e2015-06-04 17:02:31 -0700202 void _lsr(Variable *Dest, Variable *Src0, Operand *Src1,
203 CondARM32::Cond Pred = CondARM32::AL) {
204 Context.insert(InstARM32Lsr::create(Func, Dest, Src0, Src1, Pred));
205 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700206 void _mla(Variable *Dest, Variable *Src0, Variable *Src1, Variable *Acc,
207 CondARM32::Cond Pred = CondARM32::AL) {
208 Context.insert(InstARM32Mla::create(Func, Dest, Src0, Src1, Acc, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700209 }
Jan Voungb3401d22015-05-18 09:38:21 -0700210 // If Dest=nullptr is passed in, then a new variable is created,
211 // marked as infinite register allocation weight, and returned
212 // through the in/out Dest argument.
213 void _mov(Variable *&Dest, Operand *Src0,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700214 CondARM32::Cond Pred = CondARM32::AL,
Jan Voungb3401d22015-05-18 09:38:21 -0700215 int32_t RegNum = Variable::NoRegister) {
216 if (Dest == nullptr)
217 Dest = makeReg(Src0->getType(), RegNum);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700218 Context.insert(InstARM32Mov::create(Func, Dest, Src0, Pred));
219 }
220 void _mov_nonkillable(Variable *Dest, Operand *Src0,
221 CondARM32::Cond Pred = CondARM32::AL) {
222 Inst *NewInst = InstARM32Mov::create(Func, Dest, Src0, Pred);
223 NewInst->setDestNonKillable();
224 Context.insert(NewInst);
Jan Voungb3401d22015-05-18 09:38:21 -0700225 }
226 // The Operand can only be a 16-bit immediate or a ConstantRelocatable
227 // (with an upper16 relocation).
Jan Voung3bfd99a2015-05-22 16:35:25 -0700228 void _movt(Variable *Dest, Operand *Src0,
229 CondARM32::Cond Pred = CondARM32::AL) {
230 Context.insert(InstARM32Movt::create(Func, Dest, Src0, Pred));
Jan Voungb3401d22015-05-18 09:38:21 -0700231 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700232 void _movw(Variable *Dest, Operand *Src0,
233 CondARM32::Cond Pred = CondARM32::AL) {
234 Context.insert(InstARM32Movw::create(Func, Dest, Src0, Pred));
Jan Voungb3401d22015-05-18 09:38:21 -0700235 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700236 void _mul(Variable *Dest, Variable *Src0, Variable *Src1,
237 CondARM32::Cond Pred = CondARM32::AL) {
238 Context.insert(InstARM32Mul::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700239 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700240 void _mvn(Variable *Dest, Operand *Src0,
241 CondARM32::Cond Pred = CondARM32::AL) {
242 Context.insert(InstARM32Mvn::create(Func, Dest, Src0, Pred));
Jan Voungb3401d22015-05-18 09:38:21 -0700243 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700244 void _orr(Variable *Dest, Variable *Src0, Operand *Src1,
245 CondARM32::Cond Pred = CondARM32::AL) {
246 Context.insert(InstARM32Orr::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700247 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700248 void _push(const VarList &Sources) {
249 Context.insert(InstARM32Push::create(Func, Sources));
250 }
251 void _pop(const VarList &Dests) {
252 Context.insert(InstARM32Pop::create(Func, Dests));
253 // Mark dests as modified.
254 for (Variable *Dest : Dests)
255 Context.insert(InstFakeDef::create(Func, Dest));
256 }
Jan Voung66c3d5e2015-06-04 17:02:31 -0700257 void _rsb(Variable *Dest, Variable *Src0, Operand *Src1,
258 CondARM32::Cond Pred = CondARM32::AL) {
259 Context.insert(InstARM32Rsb::create(Func, Dest, Src0, Src1, Pred));
260 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700261 void _sbc(Variable *Dest, Variable *Src0, Operand *Src1,
262 CondARM32::Cond Pred = CondARM32::AL) {
263 Context.insert(InstARM32Sbc::create(Func, Dest, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700264 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700265 void _sbcs(Variable *Dest, Variable *Src0, Operand *Src1,
266 CondARM32::Cond Pred = CondARM32::AL) {
Jan Voung29719972015-05-19 11:24:51 -0700267 const bool SetFlags = true;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700268 Context.insert(
269 InstARM32Sbc::create(Func, Dest, Src0, Src1, Pred, SetFlags));
270 }
Jan Voungbefd03a2015-06-02 11:03:03 -0700271 void _str(Variable *Value, OperandARM32Mem *Addr,
272 CondARM32::Cond Pred = CondARM32::AL) {
273 Context.insert(InstARM32Str::create(Func, Value, Addr, Pred));
274 }
Jan Voung3bfd99a2015-05-22 16:35:25 -0700275 void _sub(Variable *Dest, Variable *Src0, Operand *Src1,
276 CondARM32::Cond Pred = CondARM32::AL) {
277 Context.insert(InstARM32Sub::create(Func, Dest, Src0, Src1, Pred));
278 }
279 void _subs(Variable *Dest, Variable *Src0, Operand *Src1,
280 CondARM32::Cond Pred = CondARM32::AL) {
281 const bool SetFlags = true;
282 Context.insert(
283 InstARM32Sub::create(Func, Dest, Src0, Src1, Pred, SetFlags));
Jan Voung29719972015-05-19 11:24:51 -0700284 }
Jan Voung66c3d5e2015-06-04 17:02:31 -0700285 void _sxt(Variable *Dest, Variable *Src0,
286 CondARM32::Cond Pred = CondARM32::AL) {
287 Context.insert(InstARM32Sxt::create(Func, Dest, Src0, Pred));
288 }
Jan Voungb2d50842015-05-12 09:53:50 -0700289 void _ret(Variable *LR, Variable *Src0 = nullptr) {
290 Context.insert(InstARM32Ret::create(Func, LR, Src0));
291 }
Jan Voung29719972015-05-19 11:24:51 -0700292 void _umull(Variable *DestLo, Variable *DestHi, Variable *Src0,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700293 Variable *Src1, CondARM32::Cond Pred = CondARM32::AL) {
294 Context.insert(
295 InstARM32Umull::create(Func, DestLo, DestHi, Src0, Src1, Pred));
Jan Voung29719972015-05-19 11:24:51 -0700296 // Model the modification to the second dest as a fake def.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700297 // Note that the def is not predicated.
Jan Voung29719972015-05-19 11:24:51 -0700298 Context.insert(InstFakeDef::create(Func, DestHi, DestLo));
299 }
Jan Voung66c3d5e2015-06-04 17:02:31 -0700300 void _uxt(Variable *Dest, Variable *Src0,
301 CondARM32::Cond Pred = CondARM32::AL) {
302 Context.insert(InstARM32Uxt::create(Func, Dest, Src0, Pred));
303 }
Jan Voungb2d50842015-05-12 09:53:50 -0700304
Jim Stichnotheafb56c2015-06-22 10:35:22 -0700305 ARM32InstructionSet InstructionSet = ARM32InstructionSet::Begin;
306 bool UsesFramePointer = false;
307 bool NeedsStackAlignment = false;
308 bool MaybeLeafFunc = true;
309 size_t SpillAreaSizeBytes = 0;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700310 llvm::SmallBitVector TypeToRegisterSet[IceType_NUM];
311 llvm::SmallBitVector ScratchRegs;
312 llvm::SmallBitVector RegsUsed;
313 VarList PhysicalRegisters[IceType_NUM];
314 static IceString RegNames[];
315
Jan Voungb0a8c242015-06-18 15:00:14 -0700316 // Helper class that understands the Calling Convention and register
317 // assignments. The first few integer type parameters can use r0-r3,
318 // regardless of their position relative to the floating-point/vector
319 // arguments in the argument list. Floating-point and vector arguments
320 // can use q0-q3 (aka d0-d7, s0-s15). Technically, arguments that can
321 // start with registers but extend beyond the available registers can be
322 // split between the registers and the stack. However, this is typically
323 // for passing GPR structs by value, and PNaCl transforms expand this out.
324 //
325 // Also, at the point before the call, the stack must be aligned.
326 class CallingConv {
327 CallingConv(const CallingConv &) = delete;
328 CallingConv &operator=(const CallingConv &) = delete;
329
330 public:
331 CallingConv() : NumGPRRegsUsed(0) {}
332 ~CallingConv() = default;
333
334 bool I64InRegs(std::pair<int32_t, int32_t> *Regs);
335 bool I32InReg(int32_t *Reg);
336
337 static constexpr uint32_t ARM32_MAX_GPR_ARG = 4;
338
339 private:
340 uint32_t NumGPRRegsUsed;
341 };
342
Jan Voungb36ad9b2015-04-21 17:01:49 -0700343private:
Jim Stichnothe587d942015-06-22 15:49:04 -0700344 ~TargetARM32() override = default;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700345};
346
John Porto0f86d032015-06-15 07:44:27 -0700347class TargetDataARM32 final : public TargetDataLowering {
Jan Voungb36ad9b2015-04-21 17:01:49 -0700348 TargetDataARM32() = delete;
349 TargetDataARM32(const TargetDataARM32 &) = delete;
350 TargetDataARM32 &operator=(const TargetDataARM32 &) = delete;
351
352public:
Jan Voungfb792842015-06-11 15:27:50 -0700353 static std::unique_ptr<TargetDataLowering> create(GlobalContext *Ctx) {
354 return std::unique_ptr<TargetDataLowering>(new TargetDataARM32(Ctx));
Jan Voungb36ad9b2015-04-21 17:01:49 -0700355 }
356
John Porto8b1a7052015-06-17 13:20:08 -0700357 void lowerGlobals(const VariableDeclarationList &Vars,
358 const IceString &SectionSuffix) override;
John Porto0f86d032015-06-15 07:44:27 -0700359 void lowerConstants() override;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700360
361protected:
362 explicit TargetDataARM32(GlobalContext *Ctx);
363
364private:
Jim Stichnothe587d942015-06-22 15:49:04 -0700365 ~TargetDataARM32() override = default;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700366 template <typename T> static void emitConstantPool(GlobalContext *Ctx);
367};
368
Jan Voungfb792842015-06-11 15:27:50 -0700369class TargetHeaderARM32 final : public TargetHeaderLowering {
370 TargetHeaderARM32() = delete;
371 TargetHeaderARM32(const TargetHeaderARM32 &) = delete;
372 TargetHeaderARM32 &operator=(const TargetHeaderARM32 &) = delete;
373
374public:
375 static std::unique_ptr<TargetHeaderLowering> create(GlobalContext *Ctx) {
376 return std::unique_ptr<TargetHeaderLowering>(new TargetHeaderARM32(Ctx));
377 }
378
John Porto0f86d032015-06-15 07:44:27 -0700379 void lower() override;
Jan Voungfb792842015-06-11 15:27:50 -0700380
381protected:
382 explicit TargetHeaderARM32(GlobalContext *Ctx);
383
384private:
385 ~TargetHeaderARM32() = default;
386};
387
Jan Voungb36ad9b2015-04-21 17:01:49 -0700388} // end of namespace Ice
389
390#endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_H