blob: d61d93cf0430b57ff316dd2ab95ce07b48f33acf [file] [log] [blame]
Jan Voungb36ad9b2015-04-21 17:01:49 -07001//===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===//
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//===----------------------------------------------------------------------===//
Andrew Scull9612d322015-07-06 14:53:25 -07009///
10/// \file
11/// This file implements the TargetLoweringARM32 class, which consists almost
12/// entirely of the lowering sequence for each high-level instruction.
13///
Jan Voungb36ad9b2015-04-21 17:01:49 -070014//===----------------------------------------------------------------------===//
John Porto67f8de92015-06-25 10:14:17 -070015#include "IceTargetLoweringARM32.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070016
17#include "IceCfg.h"
18#include "IceCfgNode.h"
19#include "IceClFlags.h"
20#include "IceDefs.h"
21#include "IceELFObjectWriter.h"
22#include "IceGlobalInits.h"
23#include "IceInstARM32.h"
24#include "IceLiveness.h"
25#include "IceOperand.h"
Jan Voung53483692015-07-16 10:47:46 -070026#include "IcePhiLoweringImpl.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070027#include "IceRegistersARM32.h"
28#include "IceTargetLoweringARM32.def"
Jan Voungb36ad9b2015-04-21 17:01:49 -070029#include "IceUtils.h"
John Porto67f8de92015-06-25 10:14:17 -070030#include "llvm/Support/MathExtras.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070031
John Portoa83bfde2015-09-18 08:43:02 -070032#include <algorithm>
33
Jan Voungb36ad9b2015-04-21 17:01:49 -070034namespace Ice {
35
Jan Voungb2d50842015-05-12 09:53:50 -070036namespace {
Jan Voung3bfd99a2015-05-22 16:35:25 -070037
John Portoc31e2ed2015-09-11 05:17:08 -070038// UnimplementedError is defined as a macro so that we can get actual line
39// numbers.
40#define UnimplementedError(Flags) \
41 do { \
42 if (!static_cast<const ClFlags &>(Flags).getSkipUnimplemented()) { \
43 /* Use llvm_unreachable instead of report_fatal_error, which gives \
44 better stack traces. */ \
45 llvm_unreachable("Not yet implemented"); \
46 abort(); \
47 } \
48 } while (0)
Jan Voungb3401d22015-05-18 09:38:21 -070049
Jan Voung3bfd99a2015-05-22 16:35:25 -070050// The following table summarizes the logic for lowering the icmp instruction
Andrew Scull57e12682015-09-16 11:30:19 -070051// for i32 and narrower types. Each icmp condition has a clear mapping to an
Jan Voung3bfd99a2015-05-22 16:35:25 -070052// ARM32 conditional move instruction.
53
54const struct TableIcmp32_ {
55 CondARM32::Cond Mapping;
56} TableIcmp32[] = {
57#define X(val, is_signed, swapped64, C_32, C1_64, C2_64) \
58 { CondARM32::C_32 } \
59 ,
60 ICMPARM32_TABLE
61#undef X
62};
Jan Voung3bfd99a2015-05-22 16:35:25 -070063
64// The following table summarizes the logic for lowering the icmp instruction
65// for the i64 type. Two conditional moves are needed for setting to 1 or 0.
Andrew Scull57e12682015-09-16 11:30:19 -070066// The operands may need to be swapped, and there is a slight difference for
67// signed vs unsigned (comparing hi vs lo first, and using cmp vs sbc).
Jan Voung3bfd99a2015-05-22 16:35:25 -070068const struct TableIcmp64_ {
69 bool IsSigned;
70 bool Swapped;
71 CondARM32::Cond C1, C2;
72} TableIcmp64[] = {
73#define X(val, is_signed, swapped64, C_32, C1_64, C2_64) \
74 { is_signed, swapped64, CondARM32::C1_64, CondARM32::C2_64 } \
75 ,
76 ICMPARM32_TABLE
77#undef X
78};
Jan Voung3bfd99a2015-05-22 16:35:25 -070079
80CondARM32::Cond getIcmp32Mapping(InstIcmp::ICond Cond) {
81 size_t Index = static_cast<size_t>(Cond);
Andrew Scull2c688f62015-09-09 11:56:10 -070082 assert(Index < llvm::array_lengthof(TableIcmp32));
Jan Voung3bfd99a2015-05-22 16:35:25 -070083 return TableIcmp32[Index].Mapping;
84}
85
Andrew Scull57e12682015-09-16 11:30:19 -070086// In some cases, there are x-macros tables for both high-level and low-level
87// instructions/operands that use the same enum key value. The tables are kept
88// separate to maintain a proper separation between abstraction layers. There
89// is a risk that the tables could get out of sync if enum values are reordered
John Porto2f5534f2015-09-18 15:59:47 -070090// or if entries are added or deleted. The following anonymous namespaces use
Jan Voung3bfd99a2015-05-22 16:35:25 -070091// static_asserts to ensure everything is kept in sync.
92
93// Validate the enum values in ICMPARM32_TABLE.
John Porto2f5534f2015-09-18 15:59:47 -070094namespace {
Andrew Scull57e12682015-09-16 11:30:19 -070095// Define a temporary set of enum values based on low-level table entries.
John Porto2f5534f2015-09-18 15:59:47 -070096enum _icmp_ll_enum {
97#define X(val, signed, swapped64, C_32, C1_64, C2_64) _icmp_ll_##val,
Jan Voung3bfd99a2015-05-22 16:35:25 -070098 ICMPARM32_TABLE
99#undef X
100 _num
101};
102// Define a set of constants based on high-level table entries.
John Porto2f5534f2015-09-18 15:59:47 -0700103#define X(tag, str) static constexpr int _icmp_hl_##tag = InstIcmp::tag;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700104ICEINSTICMP_TABLE
105#undef X
Andrew Scull57e12682015-09-16 11:30:19 -0700106// Define a set of constants based on low-level table entries, and ensure the
107// table entry keys are consistent.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700108#define X(val, signed, swapped64, C_32, C1_64, C2_64) \
Jan Voung3bfd99a2015-05-22 16:35:25 -0700109 static_assert( \
John Porto2f5534f2015-09-18 15:59:47 -0700110 _icmp_ll_##val == _icmp_hl_##val, \
111 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #val);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700112ICMPARM32_TABLE
113#undef X
Andrew Scull57e12682015-09-16 11:30:19 -0700114// Repeat the static asserts with respect to the high-level table entries in
115// case the high-level table has extra entries.
Jan Voung3bfd99a2015-05-22 16:35:25 -0700116#define X(tag, str) \
117 static_assert( \
John Porto2f5534f2015-09-18 15:59:47 -0700118 _icmp_hl_##tag == _icmp_ll_##tag, \
119 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #tag);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700120ICEINSTICMP_TABLE
121#undef X
John Porto2f5534f2015-09-18 15:59:47 -0700122} // end of anonymous namespace
Jan Voung3bfd99a2015-05-22 16:35:25 -0700123
Jan Voung55500db2015-05-26 14:25:40 -0700124// Stack alignment
125const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16;
126
Andrew Scull57e12682015-09-16 11:30:19 -0700127// Value is in bytes. Return Value adjusted to the next highest multiple of the
128// stack alignment.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700129uint32_t applyStackAlignment(uint32_t Value) {
130 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES);
131}
132
Andrew Scull57e12682015-09-16 11:30:19 -0700133// Value is in bytes. Return Value adjusted to the next highest multiple of the
134// stack alignment required for the given type.
Jan Voungb0a8c242015-06-18 15:00:14 -0700135uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) {
Andrew Scull57e12682015-09-16 11:30:19 -0700136 // Use natural alignment, except that normally (non-NaCl) ARM only aligns
137 // vectors to 8 bytes.
Jan Voungb0a8c242015-06-18 15:00:14 -0700138 // TODO(jvoung): Check this ...
139 size_t typeAlignInBytes = typeWidthInBytes(Ty);
140 if (isVectorType(Ty))
141 typeAlignInBytes = 8;
142 return Utils::applyAlignment(Value, typeAlignInBytes);
143}
144
Jan Voung6ec369e2015-06-30 11:03:15 -0700145// Conservatively check if at compile time we know that the operand is
146// definitely a non-zero integer.
147bool isGuaranteedNonzeroInt(const Operand *Op) {
148 if (auto *Const = llvm::dyn_cast_or_null<ConstantInteger32>(Op)) {
149 return Const->getValue() != 0;
150 }
151 return false;
152}
153
Jan Voungb2d50842015-05-12 09:53:50 -0700154} // end of anonymous namespace
155
Jan Voung6ec369e2015-06-30 11:03:15 -0700156TargetARM32Features::TargetARM32Features(const ClFlags &Flags) {
Jan Voungd062f732015-06-15 17:17:31 -0700157 static_assert(
158 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) ==
159 (TargetInstructionSet::ARM32InstructionSet_End -
160 TargetInstructionSet::ARM32InstructionSet_Begin),
161 "ARM32InstructionSet range different from TargetInstructionSet");
Jan Voung6ec369e2015-06-30 11:03:15 -0700162 if (Flags.getTargetInstructionSet() !=
Jan Voungd062f732015-06-15 17:17:31 -0700163 TargetInstructionSet::BaseInstructionSet) {
164 InstructionSet = static_cast<ARM32InstructionSet>(
Jan Voung6ec369e2015-06-30 11:03:15 -0700165 (Flags.getTargetInstructionSet() -
Jan Voungd062f732015-06-15 17:17:31 -0700166 TargetInstructionSet::ARM32InstructionSet_Begin) +
167 ARM32InstructionSet::Begin);
168 }
Jan Voung6ec369e2015-06-30 11:03:15 -0700169}
170
171TargetARM32::TargetARM32(Cfg *Func)
172 : TargetLowering(Func), CPUFeatures(Func->getContext()->getFlags()) {
Andrew Scull57e12682015-09-16 11:30:19 -0700173 // TODO: Don't initialize IntegerRegisters and friends every time. Instead,
174 // initialize in some sort of static initializer for the class.
Jan Voung86ebec12015-08-09 07:58:35 -0700175 // Limit this size (or do all bitsets need to be the same width)???
Jan Voungb36ad9b2015-04-21 17:01:49 -0700176 llvm::SmallBitVector IntegerRegisters(RegARM32::Reg_NUM);
Jan Voung86ebec12015-08-09 07:58:35 -0700177 llvm::SmallBitVector Float32Registers(RegARM32::Reg_NUM);
178 llvm::SmallBitVector Float64Registers(RegARM32::Reg_NUM);
Jan Voungb36ad9b2015-04-21 17:01:49 -0700179 llvm::SmallBitVector VectorRegisters(RegARM32::Reg_NUM);
180 llvm::SmallBitVector InvalidRegisters(RegARM32::Reg_NUM);
181 ScratchRegs.resize(RegARM32::Reg_NUM);
182#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
John Porto5300bfe2015-09-08 09:03:22 -0700183 isFP32, isFP64, isVec128, alias_init) \
Jan Voungb36ad9b2015-04-21 17:01:49 -0700184 IntegerRegisters[RegARM32::val] = isInt; \
Jan Voung86ebec12015-08-09 07:58:35 -0700185 Float32Registers[RegARM32::val] = isFP32; \
186 Float64Registers[RegARM32::val] = isFP64; \
187 VectorRegisters[RegARM32::val] = isVec128; \
John Portobb0a5fe2015-09-04 11:23:41 -0700188 RegisterAliases[RegARM32::val].resize(RegARM32::Reg_NUM); \
John Porto5300bfe2015-09-08 09:03:22 -0700189 for (SizeT RegAlias : alias_init) { \
190 assert(!RegisterAliases[RegARM32::val][RegAlias] && \
191 "Duplicate alias for " #val); \
192 RegisterAliases[RegARM32::val].set(RegAlias); \
193 } \
194 RegisterAliases[RegARM32::val].resize(RegARM32::Reg_NUM); \
195 assert(RegisterAliases[RegARM32::val][RegARM32::val]); \
Jan Voungb36ad9b2015-04-21 17:01:49 -0700196 ScratchRegs[RegARM32::val] = scratch;
197 REGARM32_TABLE;
198#undef X
199 TypeToRegisterSet[IceType_void] = InvalidRegisters;
200 TypeToRegisterSet[IceType_i1] = IntegerRegisters;
201 TypeToRegisterSet[IceType_i8] = IntegerRegisters;
202 TypeToRegisterSet[IceType_i16] = IntegerRegisters;
203 TypeToRegisterSet[IceType_i32] = IntegerRegisters;
204 TypeToRegisterSet[IceType_i64] = IntegerRegisters;
Jan Voung86ebec12015-08-09 07:58:35 -0700205 TypeToRegisterSet[IceType_f32] = Float32Registers;
206 TypeToRegisterSet[IceType_f64] = Float64Registers;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700207 TypeToRegisterSet[IceType_v4i1] = VectorRegisters;
208 TypeToRegisterSet[IceType_v8i1] = VectorRegisters;
209 TypeToRegisterSet[IceType_v16i1] = VectorRegisters;
210 TypeToRegisterSet[IceType_v16i8] = VectorRegisters;
211 TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
212 TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
213 TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
214}
215
216void TargetARM32::translateO2() {
217 TimerMarker T(TimerStack::TT_O2, Func);
218
219 // TODO(stichnot): share passes with X86?
220 // https://code.google.com/p/nativeclient/issues/detail?id=4094
221
222 if (!Ctx->getFlags().getPhiEdgeSplit()) {
223 // Lower Phi instructions.
224 Func->placePhiLoads();
225 if (Func->hasError())
226 return;
227 Func->placePhiStores();
228 if (Func->hasError())
229 return;
230 Func->deletePhis();
231 if (Func->hasError())
232 return;
233 Func->dump("After Phi lowering");
234 }
235
236 // Address mode optimization.
237 Func->getVMetadata()->init(VMK_SingleDefs);
238 Func->doAddressOpt();
239
240 // Argument lowering
241 Func->doArgLowering();
242
Andrew Scull57e12682015-09-16 11:30:19 -0700243 // Target lowering. This requires liveness analysis for some parts of the
244 // lowering decisions, such as compare/branch fusing. If non-lightweight
245 // liveness analysis is used, the instructions need to be renumbered first.
246 // TODO: This renumbering should only be necessary if we're actually
247 // calculating live intervals, which we only do for register allocation.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700248 Func->renumberInstructions();
249 if (Func->hasError())
250 return;
251
Andrew Scull57e12682015-09-16 11:30:19 -0700252 // TODO: It should be sufficient to use the fastest liveness calculation,
253 // i.e. livenessLightweight(). However, for some reason that slows down the
254 // rest of the translation. Investigate.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700255 Func->liveness(Liveness_Basic);
256 if (Func->hasError())
257 return;
258 Func->dump("After ARM32 address mode opt");
259
260 Func->genCode();
261 if (Func->hasError())
262 return;
263 Func->dump("After ARM32 codegen");
264
Andrew Scull57e12682015-09-16 11:30:19 -0700265 // Register allocation. This requires instruction renumbering and full
266 // liveness analysis.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700267 Func->renumberInstructions();
268 if (Func->hasError())
269 return;
270 Func->liveness(Liveness_Intervals);
271 if (Func->hasError())
272 return;
Andrew Scull57e12682015-09-16 11:30:19 -0700273 // Validate the live range computations. The expensive validation call is
274 // deliberately only made when assertions are enabled.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700275 assert(Func->validateLiveness());
Andrew Scull57e12682015-09-16 11:30:19 -0700276 // The post-codegen dump is done here, after liveness analysis and associated
277 // cleanup, to make the dump cleaner and more useful.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700278 Func->dump("After initial ARM32 codegen");
279 Func->getVMetadata()->init(VMK_All);
280 regAlloc(RAK_Global);
281 if (Func->hasError())
282 return;
283 Func->dump("After linear scan regalloc");
284
285 if (Ctx->getFlags().getPhiEdgeSplit()) {
286 Func->advancedPhiLowering();
287 Func->dump("After advanced Phi lowering");
288 }
289
290 // Stack frame mapping.
291 Func->genFrame();
292 if (Func->hasError())
293 return;
294 Func->dump("After stack frame mapping");
295
Jan Voung28068ad2015-07-31 12:58:46 -0700296 legalizeStackSlots();
297 if (Func->hasError())
298 return;
299 Func->dump("After legalizeStackSlots");
300
Jan Voungb36ad9b2015-04-21 17:01:49 -0700301 Func->contractEmptyNodes();
302 Func->reorderNodes();
303
Andrew Scull57e12682015-09-16 11:30:19 -0700304 // Branch optimization. This needs to be done just before code emission. In
305 // particular, no transformations that insert or reorder CfgNodes should be
306 // done after branch optimization. We go ahead and do it before nop insertion
307 // to reduce the amount of work needed for searching for opportunities.
Jan Voungb36ad9b2015-04-21 17:01:49 -0700308 Func->doBranchOpt();
309 Func->dump("After branch optimization");
310
311 // Nop insertion
312 if (Ctx->getFlags().shouldDoNopInsertion()) {
313 Func->doNopInsertion();
314 }
315}
316
317void TargetARM32::translateOm1() {
318 TimerMarker T(TimerStack::TT_Om1, Func);
319
320 // TODO: share passes with X86?
321
322 Func->placePhiLoads();
323 if (Func->hasError())
324 return;
325 Func->placePhiStores();
326 if (Func->hasError())
327 return;
328 Func->deletePhis();
329 if (Func->hasError())
330 return;
331 Func->dump("After Phi lowering");
332
333 Func->doArgLowering();
334
335 Func->genCode();
336 if (Func->hasError())
337 return;
338 Func->dump("After initial ARM32 codegen");
339
340 regAlloc(RAK_InfOnly);
341 if (Func->hasError())
342 return;
343 Func->dump("After regalloc of infinite-weight variables");
344
345 Func->genFrame();
346 if (Func->hasError())
347 return;
348 Func->dump("After stack frame mapping");
349
Jan Voung28068ad2015-07-31 12:58:46 -0700350 legalizeStackSlots();
351 if (Func->hasError())
352 return;
353 Func->dump("After legalizeStackSlots");
354
Jan Voungb36ad9b2015-04-21 17:01:49 -0700355 // Nop insertion
356 if (Ctx->getFlags().shouldDoNopInsertion()) {
357 Func->doNopInsertion();
358 }
359}
360
361bool TargetARM32::doBranchOpt(Inst *I, const CfgNode *NextNode) {
Jan Voung3bfd99a2015-05-22 16:35:25 -0700362 if (InstARM32Br *Br = llvm::dyn_cast<InstARM32Br>(I)) {
363 return Br->optimizeBranch(NextNode);
364 }
Jan Voungb2d50842015-05-12 09:53:50 -0700365 return false;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700366}
367
Jan Voungb36ad9b2015-04-21 17:01:49 -0700368IceString TargetARM32::getRegName(SizeT RegNum, Type Ty) const {
369 assert(RegNum < RegARM32::Reg_NUM);
370 (void)Ty;
Jan Voung0dab0322015-07-21 14:29:34 -0700371 static const char *RegNames[] = {
372#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
John Porto5300bfe2015-09-08 09:03:22 -0700373 isFP32, isFP64, isVec128, alias_init) \
Jan Voung0dab0322015-07-21 14:29:34 -0700374 name,
375 REGARM32_TABLE
376#undef X
377 };
378
Jan Voungb36ad9b2015-04-21 17:01:49 -0700379 return RegNames[RegNum];
380}
381
382Variable *TargetARM32::getPhysicalRegister(SizeT RegNum, Type Ty) {
383 if (Ty == IceType_void)
384 Ty = IceType_i32;
385 if (PhysicalRegisters[Ty].empty())
386 PhysicalRegisters[Ty].resize(RegARM32::Reg_NUM);
387 assert(RegNum < PhysicalRegisters[Ty].size());
388 Variable *Reg = PhysicalRegisters[Ty][RegNum];
389 if (Reg == nullptr) {
390 Reg = Func->makeVariable(Ty);
391 Reg->setRegNum(RegNum);
392 PhysicalRegisters[Ty][RegNum] = Reg;
Jim Stichnoth69660552015-09-18 06:41:02 -0700393 // Specially mark a named physical register as an "argument" so that it is
394 // considered live upon function entry. Otherwise it's possible to get
395 // liveness validation errors for saving callee-save registers.
396 Func->addImplicitArg(Reg);
397 // Don't bother tracking the live range of a named physical register.
398 Reg->setIgnoreLiveness();
Jan Voungb36ad9b2015-04-21 17:01:49 -0700399 }
400 return Reg;
401}
402
Andrew Scull86df4e92015-07-30 13:54:44 -0700403void TargetARM32::emitJumpTable(const Cfg *Func,
404 const InstJumpTable *JumpTable) const {
405 (void)JumpTable;
406 UnimplementedError(Func->getContext()->getFlags());
407}
408
Jan Voungb36ad9b2015-04-21 17:01:49 -0700409void TargetARM32::emitVariable(const Variable *Var) const {
Jan Voung28068ad2015-07-31 12:58:46 -0700410 if (!BuildDefs::dump())
411 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700412 Ostream &Str = Ctx->getStrEmit();
Jan Voungb2d50842015-05-12 09:53:50 -0700413 if (Var->hasReg()) {
414 Str << getRegName(Var->getRegNum(), Var->getType());
415 return;
416 }
Andrew Scull11c9a322015-08-28 14:24:14 -0700417 if (Var->mustHaveReg()) {
Jan Voungb2d50842015-05-12 09:53:50 -0700418 llvm::report_fatal_error(
419 "Infinite-weight Variable has no register assigned");
420 }
421 int32_t Offset = Var->getStackOffset();
Jan Voung28068ad2015-07-31 12:58:46 -0700422 int32_t BaseRegNum = Var->getBaseRegNum();
423 if (BaseRegNum == Variable::NoRegister) {
424 BaseRegNum = getFrameOrStackReg();
425 if (!hasFramePointer())
426 Offset += getStackAdjustment();
427 }
428 if (!isLegalVariableStackOffset(Offset)) {
Jan Voungb2d50842015-05-12 09:53:50 -0700429 llvm::report_fatal_error("Illegal stack offset");
430 }
Jan Voung28068ad2015-07-31 12:58:46 -0700431 const Type FrameSPTy = stackSlotType();
432 Str << "[" << getRegName(BaseRegNum, FrameSPTy);
Jan Voungb3401d22015-05-18 09:38:21 -0700433 if (Offset != 0) {
434 Str << ", " << getConstantPrefix() << Offset;
435 }
436 Str << "]";
Jan Voungb36ad9b2015-04-21 17:01:49 -0700437}
438
Jan Voungb0a8c242015-06-18 15:00:14 -0700439bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) {
440 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG)
441 return false;
442 int32_t RegLo, RegHi;
Andrew Scull57e12682015-09-16 11:30:19 -0700443 // Always start i64 registers at an even register, so this may end up padding
444 // away a register.
Jan Voung86ebec12015-08-09 07:58:35 -0700445 NumGPRRegsUsed = Utils::applyAlignment(NumGPRRegsUsed, 2);
Jan Voungb0a8c242015-06-18 15:00:14 -0700446 RegLo = RegARM32::Reg_r0 + NumGPRRegsUsed;
447 ++NumGPRRegsUsed;
448 RegHi = RegARM32::Reg_r0 + NumGPRRegsUsed;
449 ++NumGPRRegsUsed;
Andrew Scull57e12682015-09-16 11:30:19 -0700450 // If this bumps us past the boundary, don't allocate to a register and leave
451 // any previously speculatively consumed registers as consumed.
Jan Voungb0a8c242015-06-18 15:00:14 -0700452 if (NumGPRRegsUsed > ARM32_MAX_GPR_ARG)
453 return false;
454 Regs->first = RegLo;
455 Regs->second = RegHi;
456 return true;
457}
458
459bool TargetARM32::CallingConv::I32InReg(int32_t *Reg) {
460 if (NumGPRRegsUsed >= ARM32_MAX_GPR_ARG)
461 return false;
462 *Reg = RegARM32::Reg_r0 + NumGPRRegsUsed;
463 ++NumGPRRegsUsed;
464 return true;
465}
466
Jan Voung86ebec12015-08-09 07:58:35 -0700467bool TargetARM32::CallingConv::FPInReg(Type Ty, int32_t *Reg) {
John Porto385351b2015-09-16 16:11:10 -0700468 if (!VFPRegsFree.any()) {
Jan Voung86ebec12015-08-09 07:58:35 -0700469 return false;
John Porto385351b2015-09-16 16:11:10 -0700470 }
471
Jan Voung86ebec12015-08-09 07:58:35 -0700472 if (isVectorType(Ty)) {
Andrew Scull57e12682015-09-16 11:30:19 -0700473 // Q registers are declared in reverse order, so RegARM32::Reg_q0 >
John Porto385351b2015-09-16 16:11:10 -0700474 // RegARM32::Reg_q1. Therefore, we need to subtract QRegStart from Reg_q0.
475 // Same thing goes for D registers.
John Porto5300bfe2015-09-08 09:03:22 -0700476 static_assert(RegARM32::Reg_q0 > RegARM32::Reg_q1,
477 "ARM32 Q registers are possibly declared incorrectly.");
John Porto385351b2015-09-16 16:11:10 -0700478
479 int32_t QRegStart = (VFPRegsFree & ValidV128Regs).find_first();
480 if (QRegStart >= 0) {
481 VFPRegsFree.reset(QRegStart, QRegStart + 4);
482 *Reg = RegARM32::Reg_q0 - (QRegStart / 4);
483 return true;
484 }
Jan Voung86ebec12015-08-09 07:58:35 -0700485 } else if (Ty == IceType_f64) {
John Porto5300bfe2015-09-08 09:03:22 -0700486 static_assert(RegARM32::Reg_d0 > RegARM32::Reg_d1,
487 "ARM32 D registers are possibly declared incorrectly.");
John Porto385351b2015-09-16 16:11:10 -0700488
489 int32_t DRegStart = (VFPRegsFree & ValidF64Regs).find_first();
490 if (DRegStart >= 0) {
491 VFPRegsFree.reset(DRegStart, DRegStart + 2);
492 *Reg = RegARM32::Reg_d0 - (DRegStart / 2);
493 return true;
494 }
Jan Voung86ebec12015-08-09 07:58:35 -0700495 } else {
John Porto5300bfe2015-09-08 09:03:22 -0700496 static_assert(RegARM32::Reg_s0 < RegARM32::Reg_s1,
497 "ARM32 S registers are possibly declared incorrectly.");
John Porto385351b2015-09-16 16:11:10 -0700498
Jan Voung86ebec12015-08-09 07:58:35 -0700499 assert(Ty == IceType_f32);
John Porto385351b2015-09-16 16:11:10 -0700500 int32_t SReg = VFPRegsFree.find_first();
501 assert(SReg >= 0);
502 VFPRegsFree.reset(SReg);
503 *Reg = RegARM32::Reg_s0 + SReg;
504 return true;
Jan Voung86ebec12015-08-09 07:58:35 -0700505 }
John Porto385351b2015-09-16 16:11:10 -0700506
507 // Parameter allocation failed. From now on, every fp register must be placed
508 // on the stack. We clear VFRegsFree in case there are any "holes" from S and
509 // D registers.
510 VFPRegsFree.clear();
511 return false;
Jan Voung86ebec12015-08-09 07:58:35 -0700512}
513
Jan Voungb36ad9b2015-04-21 17:01:49 -0700514void TargetARM32::lowerArguments() {
Jan Voungb3401d22015-05-18 09:38:21 -0700515 VarList &Args = Func->getArgs();
Jan Voungb0a8c242015-06-18 15:00:14 -0700516 TargetARM32::CallingConv CC;
Jan Voungb3401d22015-05-18 09:38:21 -0700517
Andrew Scull57e12682015-09-16 11:30:19 -0700518 // For each register argument, replace Arg in the argument list with the home
519 // register. Then generate an instruction in the prolog to copy the home
520 // register to the assigned location of Arg.
Jan Voungb3401d22015-05-18 09:38:21 -0700521 Context.init(Func->getEntryNode());
522 Context.setInsertPoint(Context.getCur());
523
524 for (SizeT I = 0, E = Args.size(); I < E; ++I) {
525 Variable *Arg = Args[I];
526 Type Ty = Arg->getType();
Jan Voung86ebec12015-08-09 07:58:35 -0700527 if (Ty == IceType_i64) {
Jan Voungb0a8c242015-06-18 15:00:14 -0700528 std::pair<int32_t, int32_t> RegPair;
529 if (!CC.I64InRegs(&RegPair))
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700530 continue;
Jan Voungb3401d22015-05-18 09:38:21 -0700531 Variable *RegisterArg = Func->makeVariable(Ty);
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700532 auto *RegisterArg64On32 = llvm::cast<Variable64On32>(RegisterArg);
533 if (BuildDefs::dump())
534 RegisterArg64On32->setName(Func, "home_reg:" + Arg->getName(Func));
535 RegisterArg64On32->initHiLo(Func);
536 RegisterArg64On32->setIsArg();
537 RegisterArg64On32->getLo()->setRegNum(RegPair.first);
538 RegisterArg64On32->getHi()->setRegNum(RegPair.second);
Jan Voungb3401d22015-05-18 09:38:21 -0700539 Arg->setIsArg(false);
540
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700541 Args[I] = RegisterArg64On32;
Jan Voungb3401d22015-05-18 09:38:21 -0700542 Context.insert(InstAssign::create(Func, Arg, RegisterArg));
543 continue;
544 } else {
Jan Voungb0a8c242015-06-18 15:00:14 -0700545 int32_t RegNum;
Jan Voung86ebec12015-08-09 07:58:35 -0700546 if (isVectorType(Ty) || isFloatingType(Ty)) {
547 if (!CC.FPInReg(Ty, &RegNum))
548 continue;
549 } else {
550 assert(Ty == IceType_i32);
551 if (!CC.I32InReg(&RegNum))
552 continue;
553 }
Jan Voungb3401d22015-05-18 09:38:21 -0700554 Variable *RegisterArg = Func->makeVariable(Ty);
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700555 if (BuildDefs::dump()) {
Jan Voungb3401d22015-05-18 09:38:21 -0700556 RegisterArg->setName(Func, "home_reg:" + Arg->getName(Func));
557 }
558 RegisterArg->setRegNum(RegNum);
559 RegisterArg->setIsArg();
560 Arg->setIsArg(false);
561
562 Args[I] = RegisterArg;
563 Context.insert(InstAssign::create(Func, Arg, RegisterArg));
Jan Voung86ebec12015-08-09 07:58:35 -0700564 continue;
Jan Voungb3401d22015-05-18 09:38:21 -0700565 }
566 }
Jan Voungb36ad9b2015-04-21 17:01:49 -0700567}
568
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700569// Helper function for addProlog().
570//
Andrew Scull57e12682015-09-16 11:30:19 -0700571// This assumes Arg is an argument passed on the stack. This sets the frame
572// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
573// I64 arg that has been split into Lo and Hi components, it calls itself
574// recursively on the components, taking care to handle Lo first because of the
575// little-endian architecture. Lastly, this function generates an instruction
576// to copy Arg into its assigned register if applicable.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700577void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
578 size_t BasicFrameOffset,
579 size_t &InArgsSizeBytes) {
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700580 if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
581 Variable *Lo = Arg64On32->getLo();
582 Variable *Hi = Arg64On32->getHi();
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700583 finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, InArgsSizeBytes);
584 finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, InArgsSizeBytes);
585 return;
586 }
Andrew Scull6d47bcd2015-09-17 17:10:05 -0700587 Type Ty = Arg->getType();
Jan Voungb0a8c242015-06-18 15:00:14 -0700588 InArgsSizeBytes = applyStackAlignmentTy(InArgsSizeBytes, Ty);
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700589 Arg->setStackOffset(BasicFrameOffset + InArgsSizeBytes);
590 InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
Andrew Scull57e12682015-09-16 11:30:19 -0700591 // If the argument variable has been assigned a register, we need to load the
592 // value from the stack slot.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700593 if (Arg->hasReg()) {
594 assert(Ty != IceType_i64);
595 OperandARM32Mem *Mem = OperandARM32Mem::create(
596 Func, Ty, FramePtr, llvm::cast<ConstantInteger32>(
597 Ctx->getConstantInt32(Arg->getStackOffset())));
598 if (isVectorType(Arg->getType())) {
Jan Voung86ebec12015-08-09 07:58:35 -0700599 // Use vld1.$elem or something?
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700600 UnimplementedError(Func->getContext()->getFlags());
Jan Voung86ebec12015-08-09 07:58:35 -0700601 } else if (isFloatingType(Arg->getType())) {
602 _vldr(Arg, Mem);
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700603 } else {
604 _ldr(Arg, Mem);
605 }
Andrew Scull57e12682015-09-16 11:30:19 -0700606 // This argument-copying instruction uses an explicit OperandARM32Mem
607 // operand instead of a Variable, so its fill-from-stack operation has to
608 // be tracked separately for statistics.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700609 Ctx->statsUpdateFills();
610 }
611}
612
Jan Voungb36ad9b2015-04-21 17:01:49 -0700613Type TargetARM32::stackSlotType() { return IceType_i32; }
614
615void TargetARM32::addProlog(CfgNode *Node) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700616 // Stack frame layout:
617 //
618 // +------------------------+
619 // | 1. preserved registers |
620 // +------------------------+
621 // | 2. padding |
Jan Voung28068ad2015-07-31 12:58:46 -0700622 // +------------------------+ <--- FramePointer (if used)
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700623 // | 3. global spill area |
624 // +------------------------+
625 // | 4. padding |
626 // +------------------------+
627 // | 5. local spill area |
628 // +------------------------+
629 // | 6. padding |
630 // +------------------------+
631 // | 7. allocas |
Jan Voung28068ad2015-07-31 12:58:46 -0700632 // +------------------------+ <--- StackPointer
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700633 //
634 // The following variables record the size in bytes of the given areas:
635 // * PreservedRegsSizeBytes: area 1
636 // * SpillAreaPaddingBytes: area 2
637 // * GlobalsSize: area 3
638 // * GlobalsAndSubsequentPaddingSize: areas 3 - 4
639 // * LocalsSpillAreaSize: area 5
640 // * SpillAreaSizeBytes: areas 2 - 6
Andrew Scull57e12682015-09-16 11:30:19 -0700641 // Determine stack frame offsets for each Variable without a register
642 // assignment. This can be done as one variable per stack slot. Or, do
643 // coalescing by running the register allocator again with an infinite set of
644 // registers (as a side effect, this gives variables a second chance at
645 // physical register assignment).
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700646 //
Andrew Scull57e12682015-09-16 11:30:19 -0700647 // A middle ground approach is to leverage sparsity and allocate one block of
648 // space on the frame for globals (variables with multi-block lifetime), and
649 // one block to share for locals (single-block lifetime).
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700650
651 Context.init(Node);
652 Context.setInsertPoint(Context.getCur());
653
654 llvm::SmallBitVector CalleeSaves =
655 getRegisterSet(RegSet_CalleeSave, RegSet_None);
656 RegsUsed = llvm::SmallBitVector(CalleeSaves.size());
657 VarList SortedSpilledVariables;
658 size_t GlobalsSize = 0;
Andrew Scull57e12682015-09-16 11:30:19 -0700659 // If there is a separate locals area, this represents that area. Otherwise
660 // it counts any variable not counted by GlobalsSize.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700661 SpillAreaSizeBytes = 0;
Andrew Scull57e12682015-09-16 11:30:19 -0700662 // If there is a separate locals area, this specifies the alignment for it.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700663 uint32_t LocalsSlotsAlignmentBytes = 0;
Andrew Scull57e12682015-09-16 11:30:19 -0700664 // The entire spill locations area gets aligned to largest natural alignment
665 // of the variables that have a spill slot.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700666 uint32_t SpillAreaAlignmentBytes = 0;
667 // For now, we don't have target-specific variables that need special
668 // treatment (no stack-slot-linked SpillVariable type).
669 std::function<bool(Variable *)> TargetVarHook =
670 [](Variable *) { return false; };
671
672 // Compute the list of spilled variables and bounds for GlobalsSize, etc.
673 getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
674 &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
675 &LocalsSlotsAlignmentBytes, TargetVarHook);
676 uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
677 SpillAreaSizeBytes += GlobalsSize;
678
Andrew Scull57e12682015-09-16 11:30:19 -0700679 // Add push instructions for preserved registers. On ARM, "push" can push a
680 // whole list of GPRs via a bitmask (0-15). Unlike x86, ARM also has
681 // callee-saved float/vector registers. The "vpush" instruction can handle a
682 // whole list of float/vector registers, but it only handles contiguous
683 // sequences of registers by specifying the start and the length.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700684 VarList GPRsToPreserve;
685 GPRsToPreserve.reserve(CalleeSaves.size());
686 uint32_t NumCallee = 0;
687 size_t PreservedRegsSizeBytes = 0;
688 // Consider FP and LR as callee-save / used as needed.
689 if (UsesFramePointer) {
690 CalleeSaves[RegARM32::Reg_fp] = true;
691 assert(RegsUsed[RegARM32::Reg_fp] == false);
692 RegsUsed[RegARM32::Reg_fp] = true;
693 }
694 if (!MaybeLeafFunc) {
695 CalleeSaves[RegARM32::Reg_lr] = true;
696 RegsUsed[RegARM32::Reg_lr] = true;
697 }
698 for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
699 if (CalleeSaves[i] && RegsUsed[i]) {
Andrew Scull57e12682015-09-16 11:30:19 -0700700 // TODO(jvoung): do separate vpush for each floating point register
701 // segment and += 4, or 8 depending on type.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700702 ++NumCallee;
703 PreservedRegsSizeBytes += 4;
704 GPRsToPreserve.push_back(getPhysicalRegister(i));
705 }
706 }
707 Ctx->statsUpdateRegistersSaved(NumCallee);
708 if (!GPRsToPreserve.empty())
709 _push(GPRsToPreserve);
710
711 // Generate "mov FP, SP" if needed.
712 if (UsesFramePointer) {
713 Variable *FP = getPhysicalRegister(RegARM32::Reg_fp);
714 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
715 _mov(FP, SP);
716 // Keep FP live for late-stage liveness analysis (e.g. asm-verbose mode).
717 Context.insert(InstFakeUse::create(Func, FP));
718 }
719
Andrew Scull57e12682015-09-16 11:30:19 -0700720 // Align the variables area. SpillAreaPaddingBytes is the size of the region
721 // after the preserved registers and before the spill areas.
722 // LocalsSlotsPaddingBytes is the amount of padding between the globals and
723 // locals area if they are separate.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700724 assert(SpillAreaAlignmentBytes <= ARM32_STACK_ALIGNMENT_BYTES);
725 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
726 uint32_t SpillAreaPaddingBytes = 0;
727 uint32_t LocalsSlotsPaddingBytes = 0;
728 alignStackSpillAreas(PreservedRegsSizeBytes, SpillAreaAlignmentBytes,
729 GlobalsSize, LocalsSlotsAlignmentBytes,
730 &SpillAreaPaddingBytes, &LocalsSlotsPaddingBytes);
731 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
732 uint32_t GlobalsAndSubsequentPaddingSize =
733 GlobalsSize + LocalsSlotsPaddingBytes;
734
735 // Align SP if necessary.
736 if (NeedsStackAlignment) {
737 uint32_t StackOffset = PreservedRegsSizeBytes;
738 uint32_t StackSize = applyStackAlignment(StackOffset + SpillAreaSizeBytes);
739 SpillAreaSizeBytes = StackSize - StackOffset;
740 }
741
742 // Generate "sub sp, SpillAreaSizeBytes"
743 if (SpillAreaSizeBytes) {
Jan Voung28068ad2015-07-31 12:58:46 -0700744 // Use the scratch register if needed to legalize the immediate.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700745 Operand *SubAmount = legalize(Ctx->getConstantInt32(SpillAreaSizeBytes),
Jan Voung28068ad2015-07-31 12:58:46 -0700746 Legal_Reg | Legal_Flex, getReservedTmpReg());
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700747 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
748 _sub(SP, SP, SubAmount);
749 }
750 Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
751
752 resetStackAdjustment();
753
Andrew Scull57e12682015-09-16 11:30:19 -0700754 // Fill in stack offsets for stack args, and copy args into registers for
755 // those that were register-allocated. Args are pushed right to left, so
756 // Arg[0] is closest to the stack/frame pointer.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700757 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg());
758 size_t BasicFrameOffset = PreservedRegsSizeBytes;
759 if (!UsesFramePointer)
760 BasicFrameOffset += SpillAreaSizeBytes;
761
762 const VarList &Args = Func->getArgs();
763 size_t InArgsSizeBytes = 0;
Jan Voungb0a8c242015-06-18 15:00:14 -0700764 TargetARM32::CallingConv CC;
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700765 for (Variable *Arg : Args) {
766 Type Ty = Arg->getType();
Jan Voungb0a8c242015-06-18 15:00:14 -0700767 bool InRegs = false;
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700768 // Skip arguments passed in registers.
Jan Voung86ebec12015-08-09 07:58:35 -0700769 if (isVectorType(Ty) || isFloatingType(Ty)) {
770 int32_t DummyReg;
771 InRegs = CC.FPInReg(Ty, &DummyReg);
Jan Voungb0a8c242015-06-18 15:00:14 -0700772 } else if (Ty == IceType_i64) {
773 std::pair<int32_t, int32_t> DummyRegs;
774 InRegs = CC.I64InRegs(&DummyRegs);
775 } else {
776 assert(Ty == IceType_i32);
777 int32_t DummyReg;
778 InRegs = CC.I32InReg(&DummyReg);
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700779 }
Jan Voungb0a8c242015-06-18 15:00:14 -0700780 if (!InRegs)
781 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, InArgsSizeBytes);
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700782 }
783
784 // Fill in stack offsets for locals.
785 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
786 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
787 UsesFramePointer);
788 this->HasComputedFrame = true;
789
Jim Stichnoth20b71f52015-06-24 15:52:24 -0700790 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700791 OstreamLocker L(Func->getContext());
792 Ostream &Str = Func->getContext()->getStrDump();
793
794 Str << "Stack layout:\n";
795 uint32_t SPAdjustmentPaddingSize =
796 SpillAreaSizeBytes - LocalsSpillAreaSize -
797 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes;
798 Str << " in-args = " << InArgsSizeBytes << " bytes\n"
799 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
800 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
801 << " globals spill area = " << GlobalsSize << " bytes\n"
802 << " globals-locals spill areas intermediate padding = "
803 << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
804 << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
805 << " SP alignment padding = " << SPAdjustmentPaddingSize << " bytes\n";
806
807 Str << "Stack details:\n"
808 << " SP adjustment = " << SpillAreaSizeBytes << " bytes\n"
809 << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
810 << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
811 << " bytes\n"
812 << " is FP based = " << UsesFramePointer << "\n";
813 }
Jan Voungb36ad9b2015-04-21 17:01:49 -0700814}
815
816void TargetARM32::addEpilog(CfgNode *Node) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700817 InstList &Insts = Node->getInsts();
818 InstList::reverse_iterator RI, E;
819 for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
820 if (llvm::isa<InstARM32Ret>(*RI))
821 break;
822 }
823 if (RI == E)
824 return;
825
Andrew Scull57e12682015-09-16 11:30:19 -0700826 // Convert the reverse_iterator position into its corresponding (forward)
827 // iterator position.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700828 InstList::iterator InsertPoint = RI.base();
829 --InsertPoint;
830 Context.init(Node);
831 Context.setInsertPoint(InsertPoint);
832
833 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
834 if (UsesFramePointer) {
835 Variable *FP = getPhysicalRegister(RegARM32::Reg_fp);
Andrew Scull57e12682015-09-16 11:30:19 -0700836 // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
837 // use of SP before the assignment of SP=FP keeps previous SP adjustments
838 // from being dead-code eliminated.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700839 Context.insert(InstFakeUse::create(Func, SP));
840 _mov(SP, FP);
841 } else {
842 // add SP, SpillAreaSizeBytes
843 if (SpillAreaSizeBytes) {
Jan Voung28068ad2015-07-31 12:58:46 -0700844 // Use the scratch register if needed to legalize the immediate.
845 Operand *AddAmount =
846 legalize(Ctx->getConstantInt32(SpillAreaSizeBytes),
847 Legal_Reg | Legal_Flex, getReservedTmpReg());
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700848 _add(SP, SP, AddAmount);
849 }
850 }
851
852 // Add pop instructions for preserved registers.
853 llvm::SmallBitVector CalleeSaves =
854 getRegisterSet(RegSet_CalleeSave, RegSet_None);
855 VarList GPRsToRestore;
856 GPRsToRestore.reserve(CalleeSaves.size());
857 // Consider FP and LR as callee-save / used as needed.
858 if (UsesFramePointer) {
859 CalleeSaves[RegARM32::Reg_fp] = true;
860 }
861 if (!MaybeLeafFunc) {
862 CalleeSaves[RegARM32::Reg_lr] = true;
863 }
Andrew Scull57e12682015-09-16 11:30:19 -0700864 // Pop registers in ascending order just like push (instead of in reverse
865 // order).
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700866 for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
867 if (CalleeSaves[i] && RegsUsed[i]) {
868 GPRsToRestore.push_back(getPhysicalRegister(i));
869 }
870 }
871 if (!GPRsToRestore.empty())
872 _pop(GPRsToRestore);
873
874 if (!Ctx->getFlags().getUseSandboxing())
875 return;
876
877 // Change the original ret instruction into a sandboxed return sequence.
878 // bundle_lock
879 // bic lr, #0xc000000f
880 // bx lr
881 // bundle_unlock
882 // This isn't just aligning to the getBundleAlignLog2Bytes(). It needs to
883 // restrict to the lower 1GB as well.
884 Operand *RetMask =
885 legalize(Ctx->getConstantInt32(0xc000000f), Legal_Reg | Legal_Flex);
886 Variable *LR = makeReg(IceType_i32, RegARM32::Reg_lr);
887 Variable *RetValue = nullptr;
888 if (RI->getSrcSize())
889 RetValue = llvm::cast<Variable>(RI->getSrc(0));
890 _bundle_lock();
891 _bic(LR, LR, RetMask);
892 _ret(LR, RetValue);
893 _bundle_unlock();
894 RI->setDeleted();
Jan Voungb36ad9b2015-04-21 17:01:49 -0700895}
896
Jan Voung28068ad2015-07-31 12:58:46 -0700897bool TargetARM32::isLegalVariableStackOffset(int32_t Offset) const {
898 constexpr bool SignExt = false;
Andrew Scull57e12682015-09-16 11:30:19 -0700899 // TODO(jvoung): vldr of FP stack slots has a different limit from the plain
900 // stackSlotType().
Jan Voung28068ad2015-07-31 12:58:46 -0700901 return OperandARM32Mem::canHoldOffset(stackSlotType(), SignExt, Offset);
902}
903
904StackVariable *TargetARM32::legalizeVariableSlot(Variable *Var,
905 Variable *OrigBaseReg) {
906 int32_t Offset = Var->getStackOffset();
Andrew Scull57e12682015-09-16 11:30:19 -0700907 // Legalize will likely need a movw/movt combination, but if the top bits are
908 // all 0 from negating the offset and subtracting, we could use that instead.
Jan Voung28068ad2015-07-31 12:58:46 -0700909 bool ShouldSub = (-Offset & 0xFFFF0000) == 0;
910 if (ShouldSub)
911 Offset = -Offset;
912 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset),
913 Legal_Reg | Legal_Flex, getReservedTmpReg());
914 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg());
915 if (ShouldSub)
916 _sub(ScratchReg, OrigBaseReg, OffsetVal);
917 else
918 _add(ScratchReg, OrigBaseReg, OffsetVal);
919 StackVariable *NewVar = Func->makeVariable<StackVariable>(stackSlotType());
Andrew Scull11c9a322015-08-28 14:24:14 -0700920 NewVar->setMustNotHaveReg();
Jan Voung28068ad2015-07-31 12:58:46 -0700921 NewVar->setBaseRegNum(ScratchReg->getRegNum());
922 constexpr int32_t NewOffset = 0;
923 NewVar->setStackOffset(NewOffset);
924 return NewVar;
925}
926
927void TargetARM32::legalizeStackSlots() {
928 // If a stack variable's frame offset doesn't fit, convert from:
929 // ldr X, OFF[SP]
930 // to:
931 // movw/movt TMP, OFF_PART
932 // add TMP, TMP, SP
933 // ldr X, OFF_MORE[TMP]
934 //
935 // This is safe because we have reserved TMP, and add for ARM does not
936 // clobber the flags register.
937 Func->dump("Before legalizeStackSlots");
938 assert(hasComputedFrame());
939 // Early exit, if SpillAreaSizeBytes is really small.
940 if (isLegalVariableStackOffset(SpillAreaSizeBytes))
941 return;
942 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg());
943 int32_t StackAdjust = 0;
Andrew Scull57e12682015-09-16 11:30:19 -0700944 // Do a fairly naive greedy clustering for now. Pick the first stack slot
Jan Voung28068ad2015-07-31 12:58:46 -0700945 // that's out of bounds and make a new base reg using the architecture's temp
Andrew Scull57e12682015-09-16 11:30:19 -0700946 // register. If that works for the next slot, then great. Otherwise, create a
947 // new base register, clobbering the previous base register. Never share a
948 // base reg across different basic blocks. This isn't ideal if local and
Jan Voung28068ad2015-07-31 12:58:46 -0700949 // multi-block variables are far apart and their references are interspersed.
Andrew Scull57e12682015-09-16 11:30:19 -0700950 // It may help to be more coordinated about assign stack slot numbers and may
951 // help to assign smaller offsets to higher-weight variables so that they
952 // don't depend on this legalization.
Jan Voung28068ad2015-07-31 12:58:46 -0700953 for (CfgNode *Node : Func->getNodes()) {
954 Context.init(Node);
955 StackVariable *NewBaseReg = nullptr;
956 int32_t NewBaseOffset = 0;
957 while (!Context.atEnd()) {
958 PostIncrLoweringContext PostIncrement(Context);
959 Inst *CurInstr = Context.getCur();
960 Variable *Dest = CurInstr->getDest();
961 // Check if the previous NewBaseReg is clobbered, and reset if needed.
962 if ((Dest && NewBaseReg && Dest->hasReg() &&
963 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) ||
964 llvm::isa<InstFakeKill>(CurInstr)) {
965 NewBaseReg = nullptr;
966 NewBaseOffset = 0;
967 }
968 // The stack adjustment only matters if we are using SP instead of FP.
969 if (!hasFramePointer()) {
970 if (auto *AdjInst = llvm::dyn_cast<InstARM32AdjustStack>(CurInstr)) {
971 StackAdjust += AdjInst->getAmount();
972 NewBaseOffset += AdjInst->getAmount();
973 continue;
974 }
975 if (llvm::isa<InstARM32Call>(CurInstr)) {
976 NewBaseOffset -= StackAdjust;
977 StackAdjust = 0;
978 continue;
979 }
980 }
Andrew Scull57e12682015-09-16 11:30:19 -0700981 // For now, only Mov instructions can have stack variables. We need to
Jan Voung28068ad2015-07-31 12:58:46 -0700982 // know the type of instruction because we currently create a fresh one
983 // to replace Dest/Source, rather than mutate in place.
984 auto *MovInst = llvm::dyn_cast<InstARM32Mov>(CurInstr);
985 if (!MovInst) {
986 continue;
987 }
988 if (!Dest->hasReg()) {
989 int32_t Offset = Dest->getStackOffset();
990 Offset += StackAdjust;
991 if (!isLegalVariableStackOffset(Offset)) {
992 if (NewBaseReg) {
993 int32_t OffsetDiff = Offset - NewBaseOffset;
994 if (isLegalVariableStackOffset(OffsetDiff)) {
995 StackVariable *NewDest =
996 Func->makeVariable<StackVariable>(stackSlotType());
Andrew Scull11c9a322015-08-28 14:24:14 -0700997 NewDest->setMustNotHaveReg();
Jan Voung28068ad2015-07-31 12:58:46 -0700998 NewDest->setBaseRegNum(NewBaseReg->getBaseRegNum());
999 NewDest->setStackOffset(OffsetDiff);
1000 Variable *NewDestVar = NewDest;
1001 _mov(NewDestVar, MovInst->getSrc(0));
1002 MovInst->setDeleted();
1003 continue;
1004 }
1005 }
1006 StackVariable *LegalDest = legalizeVariableSlot(Dest, OrigBaseReg);
1007 assert(LegalDest != Dest);
1008 Variable *LegalDestVar = LegalDest;
1009 _mov(LegalDestVar, MovInst->getSrc(0));
1010 MovInst->setDeleted();
1011 NewBaseReg = LegalDest;
1012 NewBaseOffset = Offset;
1013 continue;
1014 }
1015 }
1016 assert(MovInst->getSrcSize() == 1);
1017 Variable *Var = llvm::dyn_cast<Variable>(MovInst->getSrc(0));
1018 if (Var && !Var->hasReg()) {
1019 int32_t Offset = Var->getStackOffset();
1020 Offset += StackAdjust;
1021 if (!isLegalVariableStackOffset(Offset)) {
1022 if (NewBaseReg) {
1023 int32_t OffsetDiff = Offset - NewBaseOffset;
1024 if (isLegalVariableStackOffset(OffsetDiff)) {
1025 StackVariable *NewVar =
1026 Func->makeVariable<StackVariable>(stackSlotType());
Andrew Scull11c9a322015-08-28 14:24:14 -07001027 NewVar->setMustNotHaveReg();
Jan Voung28068ad2015-07-31 12:58:46 -07001028 NewVar->setBaseRegNum(NewBaseReg->getBaseRegNum());
1029 NewVar->setStackOffset(OffsetDiff);
1030 _mov(Dest, NewVar);
1031 MovInst->setDeleted();
1032 continue;
1033 }
1034 }
1035 StackVariable *LegalVar = legalizeVariableSlot(Var, OrigBaseReg);
1036 assert(LegalVar != Var);
1037 _mov(Dest, LegalVar);
1038 MovInst->setDeleted();
1039 NewBaseReg = LegalVar;
1040 NewBaseOffset = Offset;
1041 continue;
1042 }
1043 }
1044 }
1045 }
1046}
1047
Jan Voungb3401d22015-05-18 09:38:21 -07001048Operand *TargetARM32::loOperand(Operand *Operand) {
1049 assert(Operand->getType() == IceType_i64);
1050 if (Operand->getType() != IceType_i64)
1051 return Operand;
Andrew Scull6d47bcd2015-09-17 17:10:05 -07001052 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
1053 return Var64On32->getLo();
1054 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand))
Jan Voungb3401d22015-05-18 09:38:21 -07001055 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
Jan Voungfbdd2442015-07-15 12:36:20 -07001056 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
Jan Voungb3401d22015-05-18 09:38:21 -07001057 // Conservatively disallow memory operands with side-effects (pre/post
1058 // increment) in case of duplication.
1059 assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
1060 Mem->getAddrMode() == OperandARM32Mem::NegOffset);
1061 if (Mem->isRegReg()) {
1062 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(),
1063 Mem->getIndex(), Mem->getShiftOp(),
1064 Mem->getShiftAmt(), Mem->getAddrMode());
1065 } else {
1066 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(),
1067 Mem->getOffset(), Mem->getAddrMode());
1068 }
1069 }
1070 llvm_unreachable("Unsupported operand type");
1071 return nullptr;
1072}
1073
1074Operand *TargetARM32::hiOperand(Operand *Operand) {
1075 assert(Operand->getType() == IceType_i64);
1076 if (Operand->getType() != IceType_i64)
1077 return Operand;
Andrew Scull6d47bcd2015-09-17 17:10:05 -07001078 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
1079 return Var64On32->getHi();
Jan Voungfbdd2442015-07-15 12:36:20 -07001080 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
Jan Voungb3401d22015-05-18 09:38:21 -07001081 return Ctx->getConstantInt32(
1082 static_cast<uint32_t>(Const->getValue() >> 32));
1083 }
Jan Voungfbdd2442015-07-15 12:36:20 -07001084 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
Andrew Scull57e12682015-09-16 11:30:19 -07001085 // Conservatively disallow memory operands with side-effects in case of
1086 // duplication.
Jan Voungb3401d22015-05-18 09:38:21 -07001087 assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
1088 Mem->getAddrMode() == OperandARM32Mem::NegOffset);
1089 const Type SplitType = IceType_i32;
1090 if (Mem->isRegReg()) {
1091 // We have to make a temp variable T, and add 4 to either Base or Index.
Andrew Scull57e12682015-09-16 11:30:19 -07001092 // The Index may be shifted, so adding 4 can mean something else. Thus,
1093 // prefer T := Base + 4, and use T as the new Base.
Jan Voungb3401d22015-05-18 09:38:21 -07001094 Variable *Base = Mem->getBase();
1095 Constant *Four = Ctx->getConstantInt32(4);
1096 Variable *NewBase = Func->makeVariable(Base->getType());
1097 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase,
1098 Base, Four));
1099 return OperandARM32Mem::create(Func, SplitType, NewBase, Mem->getIndex(),
1100 Mem->getShiftOp(), Mem->getShiftAmt(),
1101 Mem->getAddrMode());
1102 } else {
1103 Variable *Base = Mem->getBase();
1104 ConstantInteger32 *Offset = Mem->getOffset();
1105 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
1106 int32_t NextOffsetVal = Offset->getValue() + 4;
1107 const bool SignExt = false;
1108 if (!OperandARM32Mem::canHoldOffset(SplitType, SignExt, NextOffsetVal)) {
1109 // We have to make a temp variable and add 4 to either Base or Offset.
1110 // If we add 4 to Offset, this will convert a non-RegReg addressing
1111 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows
Andrew Scull57e12682015-09-16 11:30:19 -07001112 // RegReg addressing modes, prefer adding to base and replacing
1113 // instead. Thus we leave the old offset alone.
Jan Voungb3401d22015-05-18 09:38:21 -07001114 Constant *Four = Ctx->getConstantInt32(4);
1115 Variable *NewBase = Func->makeVariable(Base->getType());
1116 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add,
1117 NewBase, Base, Four));
1118 Base = NewBase;
1119 } else {
1120 Offset =
1121 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
1122 }
1123 return OperandARM32Mem::create(Func, SplitType, Base, Offset,
1124 Mem->getAddrMode());
1125 }
1126 }
1127 llvm_unreachable("Unsupported operand type");
1128 return nullptr;
1129}
1130
Jan Voungb36ad9b2015-04-21 17:01:49 -07001131llvm::SmallBitVector TargetARM32::getRegisterSet(RegSetMask Include,
1132 RegSetMask Exclude) const {
1133 llvm::SmallBitVector Registers(RegARM32::Reg_NUM);
1134
1135#define X(val, encode, name, scratch, preserved, stackptr, frameptr, isInt, \
John Porto5300bfe2015-09-08 09:03:22 -07001136 isFP32, isFP64, isVec128, alias_init) \
Jan Voungb36ad9b2015-04-21 17:01:49 -07001137 if (scratch && (Include & RegSet_CallerSave)) \
1138 Registers[RegARM32::val] = true; \
1139 if (preserved && (Include & RegSet_CalleeSave)) \
1140 Registers[RegARM32::val] = true; \
1141 if (stackptr && (Include & RegSet_StackPointer)) \
1142 Registers[RegARM32::val] = true; \
1143 if (frameptr && (Include & RegSet_FramePointer)) \
1144 Registers[RegARM32::val] = true; \
1145 if (scratch && (Exclude & RegSet_CallerSave)) \
1146 Registers[RegARM32::val] = false; \
1147 if (preserved && (Exclude & RegSet_CalleeSave)) \
1148 Registers[RegARM32::val] = false; \
1149 if (stackptr && (Exclude & RegSet_StackPointer)) \
1150 Registers[RegARM32::val] = false; \
1151 if (frameptr && (Exclude & RegSet_FramePointer)) \
1152 Registers[RegARM32::val] = false;
1153
1154 REGARM32_TABLE
1155
1156#undef X
1157
1158 return Registers;
1159}
1160
1161void TargetARM32::lowerAlloca(const InstAlloca *Inst) {
1162 UsesFramePointer = true;
Andrew Scull57e12682015-09-16 11:30:19 -07001163 // Conservatively require the stack to be aligned. Some stack adjustment
1164 // operations implemented below assume that the stack is aligned before the
1165 // alloca. All the alloca code ensures that the stack alignment is preserved
1166 // after the alloca. The stack alignment restriction can be relaxed in some
1167 // cases.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001168 NeedsStackAlignment = true;
Jan Voung55500db2015-05-26 14:25:40 -07001169
1170 // TODO(stichnot): minimize the number of adjustments of SP, etc.
1171 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
1172 Variable *Dest = Inst->getDest();
1173 uint32_t AlignmentParam = Inst->getAlignInBytes();
1174 // For default align=0, set it to the real value 1, to avoid any
1175 // bit-manipulation problems below.
1176 AlignmentParam = std::max(AlignmentParam, 1u);
1177
1178 // LLVM enforces power of 2 alignment.
1179 assert(llvm::isPowerOf2_32(AlignmentParam));
1180 assert(llvm::isPowerOf2_32(ARM32_STACK_ALIGNMENT_BYTES));
1181
1182 uint32_t Alignment = std::max(AlignmentParam, ARM32_STACK_ALIGNMENT_BYTES);
1183 if (Alignment > ARM32_STACK_ALIGNMENT_BYTES) {
1184 alignRegisterPow2(SP, Alignment);
1185 }
1186 Operand *TotalSize = Inst->getSizeInBytes();
1187 if (const auto *ConstantTotalSize =
1188 llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
1189 uint32_t Value = ConstantTotalSize->getValue();
1190 Value = Utils::applyAlignment(Value, Alignment);
1191 Operand *SubAmount = legalize(Ctx->getConstantInt32(Value));
1192 _sub(SP, SP, SubAmount);
1193 } else {
Andrew Scull57e12682015-09-16 11:30:19 -07001194 // Non-constant sizes need to be adjusted to the next highest multiple of
1195 // the required alignment at runtime.
Jan Voungfbdd2442015-07-15 12:36:20 -07001196 TotalSize = legalize(TotalSize, Legal_Reg | Legal_Flex);
Jan Voung55500db2015-05-26 14:25:40 -07001197 Variable *T = makeReg(IceType_i32);
1198 _mov(T, TotalSize);
1199 Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1));
1200 _add(T, T, AddAmount);
1201 alignRegisterPow2(T, Alignment);
1202 _sub(SP, SP, T);
1203 }
1204 _mov(Dest, SP);
Jan Voungb36ad9b2015-04-21 17:01:49 -07001205}
1206
Jan Voung6ec369e2015-06-30 11:03:15 -07001207void TargetARM32::div0Check(Type Ty, Operand *SrcLo, Operand *SrcHi) {
1208 if (isGuaranteedNonzeroInt(SrcLo) || isGuaranteedNonzeroInt(SrcHi))
1209 return;
Andrew Scull97f460d2015-07-21 10:07:42 -07001210 Variable *SrcLoReg = legalizeToReg(SrcLo);
Jan Voung6ec369e2015-06-30 11:03:15 -07001211 switch (Ty) {
1212 default:
1213 llvm_unreachable("Unexpected type");
1214 case IceType_i8: {
1215 Operand *Mask =
1216 legalize(Ctx->getConstantInt32(0xFF), Legal_Reg | Legal_Flex);
1217 _tst(SrcLoReg, Mask);
1218 break;
1219 }
1220 case IceType_i16: {
1221 Operand *Mask =
1222 legalize(Ctx->getConstantInt32(0xFFFF), Legal_Reg | Legal_Flex);
1223 _tst(SrcLoReg, Mask);
1224 break;
1225 }
1226 case IceType_i32: {
1227 _tst(SrcLoReg, SrcLoReg);
1228 break;
1229 }
1230 case IceType_i64: {
1231 Variable *ScratchReg = makeReg(IceType_i32);
1232 _orrs(ScratchReg, SrcLoReg, SrcHi);
Andrew Scull57e12682015-09-16 11:30:19 -07001233 // ScratchReg isn't going to be used, but we need the side-effect of
1234 // setting flags from this operation.
Jan Voung6ec369e2015-06-30 11:03:15 -07001235 Context.insert(InstFakeUse::create(Func, ScratchReg));
1236 }
1237 }
1238 InstARM32Label *Label = InstARM32Label::create(Func, this);
1239 _br(Label, CondARM32::NE);
1240 _trap();
1241 Context.insert(Label);
1242}
1243
1244void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R,
1245 Operand *Src1, ExtInstr ExtFunc,
1246 DivInstr DivFunc, const char *DivHelperName,
1247 bool IsRemainder) {
1248 div0Check(Dest->getType(), Src1, nullptr);
Andrew Scull97f460d2015-07-21 10:07:42 -07001249 Variable *Src1R = legalizeToReg(Src1);
Jan Voung6ec369e2015-06-30 11:03:15 -07001250 Variable *T0R = Src0R;
1251 Variable *T1R = Src1R;
1252 if (Dest->getType() != IceType_i32) {
1253 T0R = makeReg(IceType_i32);
1254 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL);
1255 T1R = makeReg(IceType_i32);
1256 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL);
1257 }
1258 if (hasCPUFeature(TargetARM32Features::HWDivArm)) {
1259 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL);
1260 if (IsRemainder) {
1261 Variable *T2 = makeReg(IceType_i32);
1262 _mls(T2, T, T1R, T0R);
1263 T = T2;
1264 }
1265 _mov(Dest, T);
1266 } else {
1267 constexpr SizeT MaxSrcs = 2;
1268 InstCall *Call = makeHelperCall(DivHelperName, Dest, MaxSrcs);
1269 Call->addArg(T0R);
1270 Call->addArg(T1R);
1271 lowerCall(Call);
1272 }
1273 return;
1274}
1275
Jan Voungb36ad9b2015-04-21 17:01:49 -07001276void TargetARM32::lowerArithmetic(const InstArithmetic *Inst) {
Jan Voungb3401d22015-05-18 09:38:21 -07001277 Variable *Dest = Inst->getDest();
Andrew Scull57e12682015-09-16 11:30:19 -07001278 // TODO(jvoung): Should be able to flip Src0 and Src1 if it is easier to
1279 // legalize Src0 to flex or Src1 to flex and there is a reversible
1280 // instruction. E.g., reverse subtract with immediate, register vs register,
1281 // immediate.
1282 // Or it may be the case that the operands aren't swapped, but the bits can
1283 // be flipped and a different operation applied. E.g., use BIC (bit clear)
1284 // instead of AND for some masks.
Jan Voungfbdd2442015-07-15 12:36:20 -07001285 Operand *Src0 = legalizeUndef(Inst->getSrc(0));
1286 Operand *Src1 = legalizeUndef(Inst->getSrc(1));
Jan Voungb3401d22015-05-18 09:38:21 -07001287 if (Dest->getType() == IceType_i64) {
Andrew Scull57e12682015-09-16 11:30:19 -07001288 // These helper-call-involved instructions are lowered in this separate
1289 // switch. This is because we would otherwise assume that we need to
1290 // legalize Src0 to Src0RLo and Src0Hi. However, those go unused with
1291 // helper calls, and such unused/redundant instructions will fail liveness
1292 // analysis under -Om1 setting.
Jan Voung70fa5252015-07-06 14:01:25 -07001293 switch (Inst->getOp()) {
1294 default:
1295 break;
1296 case InstArithmetic::Udiv:
1297 case InstArithmetic::Sdiv:
1298 case InstArithmetic::Urem:
1299 case InstArithmetic::Srem: {
Andrew Scull57e12682015-09-16 11:30:19 -07001300 // Check for divide by 0 (ARM normally doesn't trap, but we want it to
1301 // trap for NaCl). Src1Lo and Src1Hi may have already been legalized to a
1302 // register, which will hide a constant source operand. Instead, check
1303 // the not-yet-legalized Src1 to optimize-out a divide by 0 check.
Jan Voung70fa5252015-07-06 14:01:25 -07001304 if (auto *C64 = llvm::dyn_cast<ConstantInteger64>(Src1)) {
1305 if (C64->getValue() == 0) {
1306 _trap();
1307 return;
1308 }
1309 } else {
1310 Operand *Src1Lo = legalize(loOperand(Src1), Legal_Reg | Legal_Flex);
1311 Operand *Src1Hi = legalize(hiOperand(Src1), Legal_Reg | Legal_Flex);
1312 div0Check(IceType_i64, Src1Lo, Src1Hi);
1313 }
1314 // Technically, ARM has their own aeabi routines, but we can use the
Andrew Scull57e12682015-09-16 11:30:19 -07001315 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, but uses
1316 // the more standard __moddi3 for rem.
Jan Voung70fa5252015-07-06 14:01:25 -07001317 const char *HelperName = "";
1318 switch (Inst->getOp()) {
1319 default:
1320 llvm_unreachable("Should have only matched div ops.");
1321 break;
1322 case InstArithmetic::Udiv:
1323 HelperName = H_udiv_i64;
1324 break;
1325 case InstArithmetic::Sdiv:
1326 HelperName = H_sdiv_i64;
1327 break;
1328 case InstArithmetic::Urem:
1329 HelperName = H_urem_i64;
1330 break;
1331 case InstArithmetic::Srem:
1332 HelperName = H_srem_i64;
1333 break;
1334 }
1335 constexpr SizeT MaxSrcs = 2;
1336 InstCall *Call = makeHelperCall(HelperName, Dest, MaxSrcs);
1337 Call->addArg(Src0);
1338 Call->addArg(Src1);
1339 lowerCall(Call);
1340 return;
1341 }
1342 }
Jan Voung29719972015-05-19 11:24:51 -07001343 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
1344 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Andrew Scull97f460d2015-07-21 10:07:42 -07001345 Variable *Src0RLo = legalizeToReg(loOperand(Src0));
1346 Variable *Src0RHi = legalizeToReg(hiOperand(Src0));
Jan Voung70fa5252015-07-06 14:01:25 -07001347 Operand *Src1Lo = loOperand(Src1);
1348 Operand *Src1Hi = hiOperand(Src1);
Jan Voung29719972015-05-19 11:24:51 -07001349 Variable *T_Lo = makeReg(DestLo->getType());
1350 Variable *T_Hi = makeReg(DestHi->getType());
1351 switch (Inst->getOp()) {
1352 case InstArithmetic::_num:
1353 llvm_unreachable("Unknown arithmetic operator");
Jan Voung70fa5252015-07-06 14:01:25 -07001354 return;
Jan Voung29719972015-05-19 11:24:51 -07001355 case InstArithmetic::Add:
Jan Voung70fa5252015-07-06 14:01:25 -07001356 Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Flex);
1357 Src1Hi = legalize(Src1Hi, Legal_Reg | Legal_Flex);
Jan Voung29719972015-05-19 11:24:51 -07001358 _adds(T_Lo, Src0RLo, Src1Lo);
1359 _mov(DestLo, T_Lo);
1360 _adc(T_Hi, Src0RHi, Src1Hi);
1361 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001362 return;
Jan Voung29719972015-05-19 11:24:51 -07001363 case InstArithmetic::And:
Jan Voung70fa5252015-07-06 14:01:25 -07001364 Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Flex);
1365 Src1Hi = legalize(Src1Hi, Legal_Reg | Legal_Flex);
Jan Voung29719972015-05-19 11:24:51 -07001366 _and(T_Lo, Src0RLo, Src1Lo);
1367 _mov(DestLo, T_Lo);
1368 _and(T_Hi, Src0RHi, Src1Hi);
1369 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001370 return;
Jan Voung29719972015-05-19 11:24:51 -07001371 case InstArithmetic::Or:
Jan Voung70fa5252015-07-06 14:01:25 -07001372 Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Flex);
1373 Src1Hi = legalize(Src1Hi, Legal_Reg | Legal_Flex);
Jan Voung29719972015-05-19 11:24:51 -07001374 _orr(T_Lo, Src0RLo, Src1Lo);
1375 _mov(DestLo, T_Lo);
1376 _orr(T_Hi, Src0RHi, Src1Hi);
1377 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001378 return;
Jan Voung29719972015-05-19 11:24:51 -07001379 case InstArithmetic::Xor:
Jan Voung70fa5252015-07-06 14:01:25 -07001380 Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Flex);
1381 Src1Hi = legalize(Src1Hi, Legal_Reg | Legal_Flex);
Jan Voung29719972015-05-19 11:24:51 -07001382 _eor(T_Lo, Src0RLo, Src1Lo);
1383 _mov(DestLo, T_Lo);
1384 _eor(T_Hi, Src0RHi, Src1Hi);
1385 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001386 return;
Jan Voung29719972015-05-19 11:24:51 -07001387 case InstArithmetic::Sub:
Jan Voung70fa5252015-07-06 14:01:25 -07001388 Src1Lo = legalize(Src1Lo, Legal_Reg | Legal_Flex);
1389 Src1Hi = legalize(Src1Hi, Legal_Reg | Legal_Flex);
Jan Voung29719972015-05-19 11:24:51 -07001390 _subs(T_Lo, Src0RLo, Src1Lo);
1391 _mov(DestLo, T_Lo);
1392 _sbc(T_Hi, Src0RHi, Src1Hi);
1393 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001394 return;
Jan Voung29719972015-05-19 11:24:51 -07001395 case InstArithmetic::Mul: {
1396 // GCC 4.8 does:
1397 // a=b*c ==>
1398 // t_acc =(mul) (b.lo * c.hi)
1399 // t_acc =(mla) (c.lo * b.hi) + t_acc
1400 // t.hi,t.lo =(umull) b.lo * c.lo
1401 // t.hi += t_acc
1402 // a.lo = t.lo
1403 // a.hi = t.hi
1404 //
1405 // LLVM does:
1406 // t.hi,t.lo =(umull) b.lo * c.lo
1407 // t.hi =(mla) (b.lo * c.hi) + t.hi
1408 // t.hi =(mla) (b.hi * c.lo) + t.hi
1409 // a.lo = t.lo
1410 // a.hi = t.hi
1411 //
1412 // LLVM's lowering has fewer instructions, but more register pressure:
1413 // t.lo is live from beginning to end, while GCC delays the two-dest
1414 // instruction till the end, and kills c.hi immediately.
1415 Variable *T_Acc = makeReg(IceType_i32);
1416 Variable *T_Acc1 = makeReg(IceType_i32);
1417 Variable *T_Hi1 = makeReg(IceType_i32);
Andrew Scull97f460d2015-07-21 10:07:42 -07001418 Variable *Src1RLo = legalizeToReg(Src1Lo);
1419 Variable *Src1RHi = legalizeToReg(Src1Hi);
Jan Voung29719972015-05-19 11:24:51 -07001420 _mul(T_Acc, Src0RLo, Src1RHi);
1421 _mla(T_Acc1, Src1RLo, Src0RHi, T_Acc);
1422 _umull(T_Lo, T_Hi1, Src0RLo, Src1RLo);
1423 _add(T_Hi, T_Hi1, T_Acc1);
1424 _mov(DestLo, T_Lo);
1425 _mov(DestHi, T_Hi);
Jan Voung70fa5252015-07-06 14:01:25 -07001426 return;
1427 }
Jan Voung66c3d5e2015-06-04 17:02:31 -07001428 case InstArithmetic::Shl: {
1429 // a=b<<c ==>
1430 // GCC 4.8 does:
1431 // sub t_c1, c.lo, #32
1432 // lsl t_hi, b.hi, c.lo
1433 // orr t_hi, t_hi, b.lo, lsl t_c1
1434 // rsb t_c2, c.lo, #32
1435 // orr t_hi, t_hi, b.lo, lsr t_c2
1436 // lsl t_lo, b.lo, c.lo
1437 // a.lo = t_lo
1438 // a.hi = t_hi
Andrew Scull57e12682015-09-16 11:30:19 -07001439 // Can be strength-reduced for constant-shifts, but we don't do that for
1440 // now.
1441 // Given the sub/rsb T_C, C.lo, #32, one of the T_C will be negative. On
1442 // ARM, shifts only take the lower 8 bits of the shift register, and
1443 // saturate to the range 0-32, so the negative value will saturate to 32.
Jan Voung66c3d5e2015-06-04 17:02:31 -07001444 Variable *T_Hi = makeReg(IceType_i32);
Andrew Scull97f460d2015-07-21 10:07:42 -07001445 Variable *Src1RLo = legalizeToReg(Src1Lo);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001446 Constant *ThirtyTwo = Ctx->getConstantInt32(32);
1447 Variable *T_C1 = makeReg(IceType_i32);
1448 Variable *T_C2 = makeReg(IceType_i32);
1449 _sub(T_C1, Src1RLo, ThirtyTwo);
1450 _lsl(T_Hi, Src0RHi, Src1RLo);
1451 _orr(T_Hi, T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo,
1452 OperandARM32::LSL, T_C1));
1453 _rsb(T_C2, Src1RLo, ThirtyTwo);
1454 _orr(T_Hi, T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo,
1455 OperandARM32::LSR, T_C2));
1456 _mov(DestHi, T_Hi);
1457 Variable *T_Lo = makeReg(IceType_i32);
1458 // _mov seems to sometimes have better register preferencing than lsl.
Andrew Scull57e12682015-09-16 11:30:19 -07001459 // Otherwise mov w/ lsl shifted register is a pseudo-instruction that
1460 // maps to lsl.
Jan Voung66c3d5e2015-06-04 17:02:31 -07001461 _mov(T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo,
1462 OperandARM32::LSL, Src1RLo));
1463 _mov(DestLo, T_Lo);
Jan Voung70fa5252015-07-06 14:01:25 -07001464 return;
1465 }
Jan Voung29719972015-05-19 11:24:51 -07001466 case InstArithmetic::Lshr:
Jan Voung66c3d5e2015-06-04 17:02:31 -07001467 // a=b>>c (unsigned) ==>
1468 // GCC 4.8 does:
1469 // rsb t_c1, c.lo, #32
1470 // lsr t_lo, b.lo, c.lo
1471 // orr t_lo, t_lo, b.hi, lsl t_c1
1472 // sub t_c2, c.lo, #32
1473 // orr t_lo, t_lo, b.hi, lsr t_c2
1474 // lsr t_hi, b.hi, c.lo
1475 // a.lo = t_lo
1476 // a.hi = t_hi
1477 case InstArithmetic::Ashr: {
1478 // a=b>>c (signed) ==> ...
Andrew Scull57e12682015-09-16 11:30:19 -07001479 // Ashr is similar, but the sub t_c2, c.lo, #32 should set flags, and the
1480 // next orr should be conditioned on PLUS. The last two right shifts
1481 // should also be arithmetic.
Jan Voung66c3d5e2015-06-04 17:02:31 -07001482 bool IsAshr = Inst->getOp() == InstArithmetic::Ashr;
1483 Variable *T_Lo = makeReg(IceType_i32);
Andrew Scull97f460d2015-07-21 10:07:42 -07001484 Variable *Src1RLo = legalizeToReg(Src1Lo);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001485 Constant *ThirtyTwo = Ctx->getConstantInt32(32);
1486 Variable *T_C1 = makeReg(IceType_i32);
1487 Variable *T_C2 = makeReg(IceType_i32);
1488 _rsb(T_C1, Src1RLo, ThirtyTwo);
1489 _lsr(T_Lo, Src0RLo, Src1RLo);
1490 _orr(T_Lo, T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
1491 OperandARM32::LSL, T_C1));
1492 OperandARM32::ShiftKind RShiftKind;
1493 CondARM32::Cond Pred;
1494 if (IsAshr) {
1495 _subs(T_C2, Src1RLo, ThirtyTwo);
1496 RShiftKind = OperandARM32::ASR;
1497 Pred = CondARM32::PL;
1498 } else {
1499 _sub(T_C2, Src1RLo, ThirtyTwo);
1500 RShiftKind = OperandARM32::LSR;
1501 Pred = CondARM32::AL;
1502 }
1503 _orr(T_Lo, T_Lo, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
1504 RShiftKind, T_C2),
1505 Pred);
1506 _mov(DestLo, T_Lo);
1507 Variable *T_Hi = makeReg(IceType_i32);
1508 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
1509 RShiftKind, Src1RLo));
1510 _mov(DestHi, T_Hi);
Jan Voung6ec369e2015-06-30 11:03:15 -07001511 return;
1512 }
Jan Voung29719972015-05-19 11:24:51 -07001513 case InstArithmetic::Fadd:
1514 case InstArithmetic::Fsub:
1515 case InstArithmetic::Fmul:
1516 case InstArithmetic::Fdiv:
1517 case InstArithmetic::Frem:
1518 llvm_unreachable("FP instruction with i64 type");
Jan Voung70fa5252015-07-06 14:01:25 -07001519 return;
1520 case InstArithmetic::Udiv:
1521 case InstArithmetic::Sdiv:
1522 case InstArithmetic::Urem:
1523 case InstArithmetic::Srem:
1524 llvm_unreachable("Call-helper-involved instruction for i64 type "
1525 "should have already been handled before");
1526 return;
Jan Voung29719972015-05-19 11:24:51 -07001527 }
Jan Voung70fa5252015-07-06 14:01:25 -07001528 return;
Jan Voungb3401d22015-05-18 09:38:21 -07001529 } else if (isVectorType(Dest->getType())) {
Jan Voungb2d50842015-05-12 09:53:50 -07001530 UnimplementedError(Func->getContext()->getFlags());
Jan Voung86ebec12015-08-09 07:58:35 -07001531 // Add a fake def to keep liveness consistent in the meantime.
1532 Context.insert(InstFakeDef::create(Func, Dest));
Jan Voung70fa5252015-07-06 14:01:25 -07001533 return;
1534 }
1535 // Dest->getType() is a non-i64 scalar.
Andrew Scull97f460d2015-07-21 10:07:42 -07001536 Variable *Src0R = legalizeToReg(Src0);
Jan Voung70fa5252015-07-06 14:01:25 -07001537 Variable *T = makeReg(Dest->getType());
1538 // Handle div/rem separately. They require a non-legalized Src1 to inspect
1539 // whether or not Src1 is a non-zero constant. Once legalized it is more
1540 // difficult to determine (constant may be moved to a register).
1541 switch (Inst->getOp()) {
1542 default:
1543 break;
1544 case InstArithmetic::Udiv: {
1545 constexpr bool IsRemainder = false;
1546 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv,
1547 H_udiv_i32, IsRemainder);
1548 return;
1549 }
1550 case InstArithmetic::Sdiv: {
1551 constexpr bool IsRemainder = false;
1552 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv,
1553 H_sdiv_i32, IsRemainder);
1554 return;
1555 }
1556 case InstArithmetic::Urem: {
1557 constexpr bool IsRemainder = true;
1558 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv,
1559 H_urem_i32, IsRemainder);
1560 return;
1561 }
1562 case InstArithmetic::Srem: {
1563 constexpr bool IsRemainder = true;
1564 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv,
1565 H_srem_i32, IsRemainder);
1566 return;
1567 }
Jan Voung86ebec12015-08-09 07:58:35 -07001568 case InstArithmetic::Frem: {
1569 const SizeT MaxSrcs = 2;
1570 Type Ty = Dest->getType();
1571 InstCall *Call = makeHelperCall(
1572 isFloat32Asserting32Or64(Ty) ? H_frem_f32 : H_frem_f64, Dest, MaxSrcs);
1573 Call->addArg(Src0R);
1574 Call->addArg(Src1);
1575 lowerCall(Call);
1576 return;
1577 }
1578 }
1579
1580 // Handle floating point arithmetic separately: they require Src1 to be
1581 // legalized to a register.
1582 switch (Inst->getOp()) {
1583 default:
1584 break;
1585 case InstArithmetic::Fadd: {
1586 Variable *Src1R = legalizeToReg(Src1);
1587 _vadd(T, Src0R, Src1R);
1588 _vmov(Dest, T);
1589 return;
1590 }
1591 case InstArithmetic::Fsub: {
1592 Variable *Src1R = legalizeToReg(Src1);
1593 _vsub(T, Src0R, Src1R);
1594 _vmov(Dest, T);
1595 return;
1596 }
1597 case InstArithmetic::Fmul: {
1598 Variable *Src1R = legalizeToReg(Src1);
1599 _vmul(T, Src0R, Src1R);
1600 _vmov(Dest, T);
1601 return;
1602 }
1603 case InstArithmetic::Fdiv: {
1604 Variable *Src1R = legalizeToReg(Src1);
1605 _vdiv(T, Src0R, Src1R);
1606 _vmov(Dest, T);
1607 return;
1608 }
Jan Voung70fa5252015-07-06 14:01:25 -07001609 }
1610
1611 Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
1612 switch (Inst->getOp()) {
1613 case InstArithmetic::_num:
1614 llvm_unreachable("Unknown arithmetic operator");
1615 return;
1616 case InstArithmetic::Add:
1617 _add(T, Src0R, Src1RF);
1618 _mov(Dest, T);
1619 return;
1620 case InstArithmetic::And:
1621 _and(T, Src0R, Src1RF);
1622 _mov(Dest, T);
1623 return;
1624 case InstArithmetic::Or:
1625 _orr(T, Src0R, Src1RF);
1626 _mov(Dest, T);
1627 return;
1628 case InstArithmetic::Xor:
1629 _eor(T, Src0R, Src1RF);
1630 _mov(Dest, T);
1631 return;
1632 case InstArithmetic::Sub:
1633 _sub(T, Src0R, Src1RF);
1634 _mov(Dest, T);
1635 return;
1636 case InstArithmetic::Mul: {
Andrew Scull97f460d2015-07-21 10:07:42 -07001637 Variable *Src1R = legalizeToReg(Src1RF);
Jan Voung70fa5252015-07-06 14:01:25 -07001638 _mul(T, Src0R, Src1R);
1639 _mov(Dest, T);
1640 return;
1641 }
1642 case InstArithmetic::Shl:
1643 _lsl(T, Src0R, Src1RF);
1644 _mov(Dest, T);
1645 return;
1646 case InstArithmetic::Lshr:
1647 _lsr(T, Src0R, Src1RF);
1648 _mov(Dest, T);
1649 return;
1650 case InstArithmetic::Ashr:
1651 _asr(T, Src0R, Src1RF);
1652 _mov(Dest, T);
1653 return;
1654 case InstArithmetic::Udiv:
1655 case InstArithmetic::Sdiv:
1656 case InstArithmetic::Urem:
1657 case InstArithmetic::Srem:
1658 llvm_unreachable("Integer div/rem should have been handled earlier.");
1659 return;
1660 case InstArithmetic::Fadd:
Jan Voung70fa5252015-07-06 14:01:25 -07001661 case InstArithmetic::Fsub:
Jan Voung70fa5252015-07-06 14:01:25 -07001662 case InstArithmetic::Fmul:
Jan Voung70fa5252015-07-06 14:01:25 -07001663 case InstArithmetic::Fdiv:
Jan Voung70fa5252015-07-06 14:01:25 -07001664 case InstArithmetic::Frem:
Jan Voung86ebec12015-08-09 07:58:35 -07001665 llvm_unreachable("Floating point arith should have been handled earlier.");
Jan Voung70fa5252015-07-06 14:01:25 -07001666 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07001667 }
1668}
1669
1670void TargetARM32::lowerAssign(const InstAssign *Inst) {
Jan Voungb3401d22015-05-18 09:38:21 -07001671 Variable *Dest = Inst->getDest();
1672 Operand *Src0 = Inst->getSrc(0);
1673 assert(Dest->getType() == Src0->getType());
1674 if (Dest->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07001675 Src0 = legalizeUndef(Src0);
1676 Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg | Legal_Flex);
1677 Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex);
Jan Voungb3401d22015-05-18 09:38:21 -07001678 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
1679 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
1680 Variable *T_Lo = nullptr, *T_Hi = nullptr;
1681 _mov(T_Lo, Src0Lo);
1682 _mov(DestLo, T_Lo);
1683 _mov(T_Hi, Src0Hi);
1684 _mov(DestHi, T_Hi);
1685 } else {
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001686 Operand *NewSrc;
Jan Voungb3401d22015-05-18 09:38:21 -07001687 if (Dest->hasReg()) {
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001688 // If Dest already has a physical register, then legalize the Src operand
Andrew Scull57e12682015-09-16 11:30:19 -07001689 // into a Variable with the same register assignment. This especially
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001690 // helps allow the use of Flex operands.
1691 NewSrc = legalize(Src0, Legal_Reg | Legal_Flex, Dest->getRegNum());
Jan Voungb3401d22015-05-18 09:38:21 -07001692 } else {
Andrew Scull57e12682015-09-16 11:30:19 -07001693 // Dest could be a stack operand. Since we could potentially need to do a
1694 // Store (and store can only have Register operands), legalize this to a
1695 // register.
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001696 NewSrc = legalize(Src0, Legal_Reg);
Jan Voungb3401d22015-05-18 09:38:21 -07001697 }
1698 if (isVectorType(Dest->getType())) {
1699 UnimplementedError(Func->getContext()->getFlags());
Jan Voung86ebec12015-08-09 07:58:35 -07001700 } else if (isFloatingType(Dest->getType())) {
1701 Variable *SrcR = legalizeToReg(NewSrc);
1702 _vmov(Dest, SrcR);
Jan Voungb3401d22015-05-18 09:38:21 -07001703 } else {
Jim Stichnotha3f57b92015-07-30 12:46:04 -07001704 _mov(Dest, NewSrc);
Jan Voungb3401d22015-05-18 09:38:21 -07001705 }
1706 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001707}
1708
1709void TargetARM32::lowerBr(const InstBr *Inst) {
Jan Voung3bfd99a2015-05-22 16:35:25 -07001710 if (Inst->isUnconditional()) {
1711 _br(Inst->getTargetUnconditional());
1712 return;
1713 }
1714 Operand *Cond = Inst->getCondition();
1715 // TODO(jvoung): Handle folding opportunities.
1716
Andrew Scull97f460d2015-07-21 10:07:42 -07001717 Variable *Src0R = legalizeToReg(Cond);
Jan Voung3bfd99a2015-05-22 16:35:25 -07001718 Constant *Zero = Ctx->getConstantZero(IceType_i32);
1719 _cmp(Src0R, Zero);
Jan Voung6ec369e2015-06-30 11:03:15 -07001720 _br(Inst->getTargetTrue(), Inst->getTargetFalse(), CondARM32::NE);
Jan Voungb36ad9b2015-04-21 17:01:49 -07001721}
1722
Jan Voung3bfd99a2015-05-22 16:35:25 -07001723void TargetARM32::lowerCall(const InstCall *Instr) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001724 MaybeLeafFunc = false;
Jan Voungb0a8c242015-06-18 15:00:14 -07001725 NeedsStackAlignment = true;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001726
Jan Voungb0a8c242015-06-18 15:00:14 -07001727 // Assign arguments to registers and stack. Also reserve stack.
1728 TargetARM32::CallingConv CC;
1729 // Pair of Arg Operand -> GPR number assignments.
1730 llvm::SmallVector<std::pair<Operand *, int32_t>,
1731 TargetARM32::CallingConv::ARM32_MAX_GPR_ARG> GPRArgs;
Jan Voung86ebec12015-08-09 07:58:35 -07001732 llvm::SmallVector<std::pair<Operand *, int32_t>,
1733 TargetARM32::CallingConv::ARM32_MAX_FP_REG_UNITS> FPArgs;
Jan Voungb0a8c242015-06-18 15:00:14 -07001734 // Pair of Arg Operand -> stack offset.
1735 llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs;
1736 int32_t ParameterAreaSizeBytes = 0;
1737
1738 // Classify each argument operand according to the location where the
1739 // argument is passed.
1740 for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
Jan Voungfbdd2442015-07-15 12:36:20 -07001741 Operand *Arg = legalizeUndef(Instr->getArg(i));
Jan Voungb0a8c242015-06-18 15:00:14 -07001742 Type Ty = Arg->getType();
1743 bool InRegs = false;
Jan Voung86ebec12015-08-09 07:58:35 -07001744 if (Ty == IceType_i64) {
Jan Voungb0a8c242015-06-18 15:00:14 -07001745 std::pair<int32_t, int32_t> Regs;
1746 if (CC.I64InRegs(&Regs)) {
1747 InRegs = true;
1748 Operand *Lo = loOperand(Arg);
1749 Operand *Hi = hiOperand(Arg);
1750 GPRArgs.push_back(std::make_pair(Lo, Regs.first));
1751 GPRArgs.push_back(std::make_pair(Hi, Regs.second));
1752 }
Jan Voung86ebec12015-08-09 07:58:35 -07001753 } else if (isVectorType(Ty) || isFloatingType(Ty)) {
1754 int32_t Reg;
1755 if (CC.FPInReg(Ty, &Reg)) {
1756 InRegs = true;
1757 FPArgs.push_back(std::make_pair(Arg, Reg));
1758 }
Jan Voungb0a8c242015-06-18 15:00:14 -07001759 } else {
1760 assert(Ty == IceType_i32);
1761 int32_t Reg;
1762 if (CC.I32InReg(&Reg)) {
1763 InRegs = true;
1764 GPRArgs.push_back(std::make_pair(Arg, Reg));
1765 }
1766 }
1767
1768 if (!InRegs) {
1769 ParameterAreaSizeBytes =
1770 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty);
1771 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes));
1772 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Arg->getType());
1773 }
1774 }
1775
Andrew Scull57e12682015-09-16 11:30:19 -07001776 // Adjust the parameter area so that the stack is aligned. It is assumed that
1777 // the stack is already aligned at the start of the calling sequence.
Jan Voungb0a8c242015-06-18 15:00:14 -07001778 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
1779
Andrew Scull57e12682015-09-16 11:30:19 -07001780 // Subtract the appropriate amount for the argument area. This also takes
1781 // care of setting the stack adjustment during emission.
Jan Voungb0a8c242015-06-18 15:00:14 -07001782 //
Andrew Scull57e12682015-09-16 11:30:19 -07001783 // TODO: If for some reason the call instruction gets dead-code eliminated
1784 // after lowering, we would need to ensure that the pre-call and the
1785 // post-call esp adjustment get eliminated as well.
Jan Voungb0a8c242015-06-18 15:00:14 -07001786 if (ParameterAreaSizeBytes) {
1787 Operand *SubAmount = legalize(Ctx->getConstantInt32(ParameterAreaSizeBytes),
1788 Legal_Reg | Legal_Flex);
1789 _adjust_stack(ParameterAreaSizeBytes, SubAmount);
1790 }
1791
Andrew Scull57e12682015-09-16 11:30:19 -07001792 // Copy arguments that are passed on the stack to the appropriate stack
1793 // locations.
Jan Voungf645d852015-07-09 10:35:09 -07001794 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
Jan Voungb0a8c242015-06-18 15:00:14 -07001795 for (auto &StackArg : StackArgs) {
1796 ConstantInteger32 *Loc =
1797 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second));
1798 Type Ty = StackArg.first->getType();
1799 OperandARM32Mem *Addr;
1800 constexpr bool SignExt = false;
1801 if (OperandARM32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) {
1802 Addr = OperandARM32Mem::create(Func, Ty, SP, Loc);
1803 } else {
1804 Variable *NewBase = Func->makeVariable(SP->getType());
1805 lowerArithmetic(
1806 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc));
1807 Addr = formMemoryOperand(NewBase, Ty);
1808 }
1809 lowerStore(InstStore::create(Func, StackArg.first, Addr));
1810 }
1811
1812 // Copy arguments to be passed in registers to the appropriate registers.
1813 for (auto &GPRArg : GPRArgs) {
Andrew Scull97f460d2015-07-21 10:07:42 -07001814 Variable *Reg = legalizeToReg(GPRArg.first, GPRArg.second);
Andrew Scull57e12682015-09-16 11:30:19 -07001815 // Generate a FakeUse of register arguments so that they do not get dead
1816 // code eliminated as a result of the FakeKill of scratch registers after
1817 // the call.
Jan Voungb0a8c242015-06-18 15:00:14 -07001818 Context.insert(InstFakeUse::create(Func, Reg));
Jan Voung3bfd99a2015-05-22 16:35:25 -07001819 }
Jan Voung86ebec12015-08-09 07:58:35 -07001820 for (auto &FPArg : FPArgs) {
1821 Variable *Reg = legalizeToReg(FPArg.first, FPArg.second);
1822 Context.insert(InstFakeUse::create(Func, Reg));
1823 }
Jan Voung3bfd99a2015-05-22 16:35:25 -07001824
Andrew Scull57e12682015-09-16 11:30:19 -07001825 // Generate the call instruction. Assign its result to a temporary with high
1826 // register allocation weight.
Jan Voung3bfd99a2015-05-22 16:35:25 -07001827 Variable *Dest = Instr->getDest();
1828 // ReturnReg doubles as ReturnRegLo as necessary.
1829 Variable *ReturnReg = nullptr;
1830 Variable *ReturnRegHi = nullptr;
1831 if (Dest) {
1832 switch (Dest->getType()) {
1833 case IceType_NUM:
1834 llvm_unreachable("Invalid Call dest type");
1835 break;
1836 case IceType_void:
1837 break;
1838 case IceType_i1:
1839 case IceType_i8:
1840 case IceType_i16:
1841 case IceType_i32:
1842 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_r0);
1843 break;
1844 case IceType_i64:
1845 ReturnReg = makeReg(IceType_i32, RegARM32::Reg_r0);
1846 ReturnRegHi = makeReg(IceType_i32, RegARM32::Reg_r1);
1847 break;
1848 case IceType_f32:
Jan Voung86ebec12015-08-09 07:58:35 -07001849 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_s0);
1850 break;
Jan Voung3bfd99a2015-05-22 16:35:25 -07001851 case IceType_f64:
Jan Voung86ebec12015-08-09 07:58:35 -07001852 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_d0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07001853 break;
1854 case IceType_v4i1:
1855 case IceType_v8i1:
1856 case IceType_v16i1:
1857 case IceType_v16i8:
1858 case IceType_v8i16:
1859 case IceType_v4i32:
1860 case IceType_v4f32:
Jan Voung86ebec12015-08-09 07:58:35 -07001861 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_q0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07001862 break;
1863 }
1864 }
1865 Operand *CallTarget = Instr->getCallTarget();
Andrew Scull57e12682015-09-16 11:30:19 -07001866 // TODO(jvoung): Handle sandboxing. const bool NeedSandboxing =
1867 // Ctx->getFlags().getUseSandboxing();
Jan Voungb0a8c242015-06-18 15:00:14 -07001868
Andrew Scull57e12682015-09-16 11:30:19 -07001869 // Allow ConstantRelocatable to be left alone as a direct call, but force
1870 // other constants like ConstantInteger32 to be in a register and make it an
1871 // indirect call.
Jan Voung3bfd99a2015-05-22 16:35:25 -07001872 if (!llvm::isa<ConstantRelocatable>(CallTarget)) {
1873 CallTarget = legalize(CallTarget, Legal_Reg);
1874 }
1875 Inst *NewCall = InstARM32Call::create(Func, ReturnReg, CallTarget);
1876 Context.insert(NewCall);
1877 if (ReturnRegHi)
1878 Context.insert(InstFakeDef::create(Func, ReturnRegHi));
1879
Andrew Scull57e12682015-09-16 11:30:19 -07001880 // Add the appropriate offset to SP. The call instruction takes care of
1881 // resetting the stack offset during emission.
Jan Voungb0a8c242015-06-18 15:00:14 -07001882 if (ParameterAreaSizeBytes) {
1883 Operand *AddAmount = legalize(Ctx->getConstantInt32(ParameterAreaSizeBytes),
1884 Legal_Reg | Legal_Flex);
Jan Voungf645d852015-07-09 10:35:09 -07001885 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
Jan Voungb0a8c242015-06-18 15:00:14 -07001886 _add(SP, SP, AddAmount);
1887 }
1888
Jan Voung3bfd99a2015-05-22 16:35:25 -07001889 // Insert a register-kill pseudo instruction.
1890 Context.insert(InstFakeKill::create(Func, NewCall));
1891
1892 // Generate a FakeUse to keep the call live if necessary.
1893 if (Instr->hasSideEffects() && ReturnReg) {
1894 Inst *FakeUse = InstFakeUse::create(Func, ReturnReg);
1895 Context.insert(FakeUse);
1896 }
1897
1898 if (!Dest)
1899 return;
1900
1901 // Assign the result of the call to Dest.
1902 if (ReturnReg) {
1903 if (ReturnRegHi) {
Andrew Scull6d47bcd2015-09-17 17:10:05 -07001904 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
1905 Variable *DestLo = Dest64On32->getLo();
1906 Variable *DestHi = Dest64On32->getHi();
Jan Voung3bfd99a2015-05-22 16:35:25 -07001907 _mov(DestLo, ReturnReg);
1908 _mov(DestHi, ReturnRegHi);
1909 } else {
Jan Voung3bfd99a2015-05-22 16:35:25 -07001910 if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) {
Jan Voung86ebec12015-08-09 07:58:35 -07001911 _vmov(Dest, ReturnReg);
Jan Voung3bfd99a2015-05-22 16:35:25 -07001912 } else {
Jan Voung86ebec12015-08-09 07:58:35 -07001913 assert(isIntegerType(Dest->getType()) &&
1914 typeWidthInBytes(Dest->getType()) <= 4);
Jan Voung3bfd99a2015-05-22 16:35:25 -07001915 _mov(Dest, ReturnReg);
1916 }
1917 }
1918 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001919}
1920
1921void TargetARM32::lowerCast(const InstCast *Inst) {
1922 InstCast::OpKind CastKind = Inst->getCastKind();
Jan Voung66c3d5e2015-06-04 17:02:31 -07001923 Variable *Dest = Inst->getDest();
Jan Voungfbdd2442015-07-15 12:36:20 -07001924 Operand *Src0 = legalizeUndef(Inst->getSrc(0));
Jan Voungb36ad9b2015-04-21 17:01:49 -07001925 switch (CastKind) {
1926 default:
1927 Func->setError("Cast type not supported");
1928 return;
1929 case InstCast::Sext: {
Jan Voung66c3d5e2015-06-04 17:02:31 -07001930 if (isVectorType(Dest->getType())) {
1931 UnimplementedError(Func->getContext()->getFlags());
1932 } else if (Dest->getType() == IceType_i64) {
1933 // t1=sxtb src; t2= mov t1 asr #31; dst.lo=t1; dst.hi=t2
1934 Constant *ShiftAmt = Ctx->getConstantInt32(31);
1935 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
1936 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
1937 Variable *T_Lo = makeReg(DestLo->getType());
1938 if (Src0->getType() == IceType_i32) {
1939 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
1940 _mov(T_Lo, Src0RF);
1941 } else if (Src0->getType() == IceType_i1) {
Andrew Scull97f460d2015-07-21 10:07:42 -07001942 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001943 _lsl(T_Lo, Src0R, ShiftAmt);
1944 _asr(T_Lo, T_Lo, ShiftAmt);
1945 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07001946 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001947 _sxt(T_Lo, Src0R);
1948 }
1949 _mov(DestLo, T_Lo);
1950 Variable *T_Hi = makeReg(DestHi->getType());
1951 if (Src0->getType() != IceType_i1) {
1952 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, T_Lo,
1953 OperandARM32::ASR, ShiftAmt));
1954 } else {
1955 // For i1, the asr instruction is already done above.
1956 _mov(T_Hi, T_Lo);
1957 }
1958 _mov(DestHi, T_Hi);
1959 } else if (Src0->getType() == IceType_i1) {
1960 // GPR registers are 32-bit, so just use 31 as dst_bitwidth - 1.
1961 // lsl t1, src_reg, 31
1962 // asr t1, t1, 31
1963 // dst = t1
Andrew Scull97f460d2015-07-21 10:07:42 -07001964 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001965 Constant *ShiftAmt = Ctx->getConstantInt32(31);
1966 Variable *T = makeReg(Dest->getType());
1967 _lsl(T, Src0R, ShiftAmt);
1968 _asr(T, T, ShiftAmt);
1969 _mov(Dest, T);
1970 } else {
1971 // t1 = sxt src; dst = t1
Andrew Scull97f460d2015-07-21 10:07:42 -07001972 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001973 Variable *T = makeReg(Dest->getType());
1974 _sxt(T, Src0R);
1975 _mov(Dest, T);
1976 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001977 break;
1978 }
1979 case InstCast::Zext: {
Jan Voung66c3d5e2015-06-04 17:02:31 -07001980 if (isVectorType(Dest->getType())) {
1981 UnimplementedError(Func->getContext()->getFlags());
1982 } else if (Dest->getType() == IceType_i64) {
1983 // t1=uxtb src; dst.lo=t1; dst.hi=0
1984 Constant *Zero = Ctx->getConstantZero(IceType_i32);
1985 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
1986 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
1987 Variable *T_Lo = makeReg(DestLo->getType());
Andrew Scull57e12682015-09-16 11:30:19 -07001988 // i32 and i1 can just take up the whole register. i32 doesn't need uxt,
1989 // while i1 will have an and mask later anyway.
Jan Voung66c3d5e2015-06-04 17:02:31 -07001990 if (Src0->getType() == IceType_i32 || Src0->getType() == IceType_i1) {
1991 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
1992 _mov(T_Lo, Src0RF);
1993 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07001994 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07001995 _uxt(T_Lo, Src0R);
1996 }
1997 if (Src0->getType() == IceType_i1) {
1998 Constant *One = Ctx->getConstantInt32(1);
1999 _and(T_Lo, T_Lo, One);
2000 }
2001 _mov(DestLo, T_Lo);
2002 Variable *T_Hi = makeReg(DestLo->getType());
2003 _mov(T_Hi, Zero);
2004 _mov(DestHi, T_Hi);
2005 } else if (Src0->getType() == IceType_i1) {
2006 // t = Src0; t &= 1; Dest = t
2007 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
2008 Constant *One = Ctx->getConstantInt32(1);
2009 Variable *T = makeReg(Dest->getType());
Andrew Scull57e12682015-09-16 11:30:19 -07002010 // Just use _mov instead of _uxt since all registers are 32-bit. _uxt
2011 // requires the source to be a register so could have required a _mov
2012 // from legalize anyway.
Jan Voung66c3d5e2015-06-04 17:02:31 -07002013 _mov(T, Src0RF);
2014 _and(T, T, One);
2015 _mov(Dest, T);
2016 } else {
2017 // t1 = uxt src; dst = t1
Andrew Scull97f460d2015-07-21 10:07:42 -07002018 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07002019 Variable *T = makeReg(Dest->getType());
2020 _uxt(T, Src0R);
2021 _mov(Dest, T);
2022 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002023 break;
2024 }
2025 case InstCast::Trunc: {
Jan Voung66c3d5e2015-06-04 17:02:31 -07002026 if (isVectorType(Dest->getType())) {
2027 UnimplementedError(Func->getContext()->getFlags());
2028 } else {
Jan Voung66c3d5e2015-06-04 17:02:31 -07002029 if (Src0->getType() == IceType_i64)
2030 Src0 = loOperand(Src0);
2031 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
2032 // t1 = trunc Src0RF; Dest = t1
2033 Variable *T = makeReg(Dest->getType());
2034 _mov(T, Src0RF);
2035 if (Dest->getType() == IceType_i1)
2036 _and(T, T, Ctx->getConstantInt1(1));
2037 _mov(Dest, T);
2038 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002039 break;
2040 }
2041 case InstCast::Fptrunc:
Jan Voungb36ad9b2015-04-21 17:01:49 -07002042 case InstCast::Fpext: {
John Portoc31e2ed2015-09-11 05:17:08 -07002043 // fptrunc: dest.f32 = fptrunc src0.fp64
2044 // fpext: dest.f64 = fptrunc src0.fp32
2045 const bool IsTrunc = CastKind == InstCast::Fptrunc;
2046 if (isVectorType(Dest->getType())) {
2047 UnimplementedError(Func->getContext()->getFlags());
2048 break;
2049 }
2050 assert(Dest->getType() == (IsTrunc ? IceType_f32 : IceType_f64));
2051 assert(Src0->getType() == (IsTrunc ? IceType_f64 : IceType_f32));
2052 Variable *Src0R = legalizeToReg(Src0);
2053 Variable *T = makeReg(Dest->getType());
2054 _vcvt(T, Src0R, IsTrunc ? InstARM32Vcvt::D2s : InstARM32Vcvt::S2d);
2055 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002056 break;
2057 }
2058 case InstCast::Fptosi:
John Portoc31e2ed2015-09-11 05:17:08 -07002059 case InstCast::Fptoui: {
2060 // fptosi:
2061 // t1.fp = vcvt src0.fp
2062 // t2.i32 = vmov t1.fp
2063 // dest.int = conv t2.i32 @ Truncates the result if needed.
2064 // fptoui:
2065 // t1.fp = vcvt src0.fp
2066 // t2.u32 = vmov t1.fp
2067 // dest.uint = conv t2.u32 @ Truncates the result if needed.
2068 if (isVectorType(Dest->getType())) {
2069 UnimplementedError(Func->getContext()->getFlags());
2070 break;
Andrew Scull6d47bcd2015-09-17 17:10:05 -07002071 }
2072 if (auto *Dest64On32 = llvm::dyn_cast<Variable64On32>(Dest)) {
2073 Context.insert(InstFakeDef::create(Func, Dest64On32->getLo()));
2074 Context.insert(InstFakeDef::create(Func, Dest64On32->getHi()));
John Portoc31e2ed2015-09-11 05:17:08 -07002075 UnimplementedError(Func->getContext()->getFlags());
2076 break;
2077 }
2078 const bool DestIsSigned = CastKind == InstCast::Fptosi;
2079 Variable *Src0R = legalizeToReg(Src0);
2080 Variable *T_fp = makeReg(IceType_f32);
2081 if (isFloat32Asserting32Or64(Src0->getType())) {
2082 _vcvt(T_fp, Src0R,
2083 DestIsSigned ? InstARM32Vcvt::S2si : InstARM32Vcvt::S2ui);
2084 } else {
2085 _vcvt(T_fp, Src0R,
2086 DestIsSigned ? InstARM32Vcvt::D2si : InstARM32Vcvt::D2ui);
2087 }
2088 Variable *T = makeReg(IceType_i32);
2089 _vmov(T, T_fp);
2090 if (Dest->getType() != IceType_i32) {
2091 Variable *T_1 = makeReg(Dest->getType());
2092 lowerCast(InstCast::create(Func, InstCast::Trunc, T_1, T));
2093 T = T_1;
2094 }
2095 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002096 break;
John Portoc31e2ed2015-09-11 05:17:08 -07002097 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002098 case InstCast::Sitofp:
Jan Voungb36ad9b2015-04-21 17:01:49 -07002099 case InstCast::Uitofp: {
John Portoc31e2ed2015-09-11 05:17:08 -07002100 // sitofp:
2101 // t1.i32 = sext src.int @ sign-extends src0 if needed.
2102 // t2.fp32 = vmov t1.i32
2103 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
2104 // uitofp:
2105 // t1.i32 = zext src.int @ zero-extends src0 if needed.
2106 // t2.fp32 = vmov t1.i32
2107 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
2108 if (isVectorType(Dest->getType())) {
2109 UnimplementedError(Func->getContext()->getFlags());
2110 break;
John Portof977f712015-09-14 16:28:33 -07002111 }
2112 if (Src0->getType() == IceType_i64) {
2113 // avoid cryptic liveness errors
2114 Context.insert(InstFakeDef::create(Func, Dest));
John Portoc31e2ed2015-09-11 05:17:08 -07002115 UnimplementedError(Func->getContext()->getFlags());
2116 break;
2117 }
2118 const bool SourceIsSigned = CastKind == InstCast::Sitofp;
2119 if (Src0->getType() != IceType_i32) {
2120 Variable *Src0R_32 = makeReg(IceType_i32);
2121 lowerCast(InstCast::create(Func, SourceIsSigned ? InstCast::Sext
2122 : InstCast::Zext,
2123 Src0R_32, Src0));
2124 Src0 = Src0R_32;
2125 }
2126 Variable *Src0R = legalizeToReg(Src0);
2127 Variable *Src0R_f32 = makeReg(IceType_f32);
2128 _vmov(Src0R_f32, Src0R);
2129 Src0R = Src0R_f32;
2130 Variable *T = makeReg(Dest->getType());
2131 if (isFloat32Asserting32Or64(Dest->getType())) {
2132 _vcvt(T, Src0R,
2133 SourceIsSigned ? InstARM32Vcvt::Si2s : InstARM32Vcvt::Ui2s);
2134 } else {
2135 _vcvt(T, Src0R,
2136 SourceIsSigned ? InstARM32Vcvt::Si2d : InstARM32Vcvt::Ui2d);
2137 }
2138 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002139 break;
2140 }
2141 case InstCast::Bitcast: {
Jan Voung66c3d5e2015-06-04 17:02:31 -07002142 Operand *Src0 = Inst->getSrc(0);
2143 if (Dest->getType() == Src0->getType()) {
2144 InstAssign *Assign = InstAssign::create(Func, Dest, Src0);
2145 lowerAssign(Assign);
2146 return;
2147 }
John Portof977f712015-09-14 16:28:33 -07002148 Type DestType = Dest->getType();
2149 switch (DestType) {
2150 case IceType_NUM:
2151 case IceType_void:
2152 llvm::report_fatal_error("Unexpected bitcast.");
2153 case IceType_i1:
2154 UnimplementedError(Func->getContext()->getFlags());
2155 break;
2156 case IceType_v4i1:
2157 UnimplementedError(Func->getContext()->getFlags());
2158 break;
2159 case IceType_i8:
2160 UnimplementedError(Func->getContext()->getFlags());
2161 break;
2162 case IceType_i16:
2163 UnimplementedError(Func->getContext()->getFlags());
2164 break;
2165 case IceType_i32:
2166 case IceType_f32: {
2167 Variable *Src0R = legalizeToReg(Src0);
2168 Variable *T = makeReg(DestType);
2169 _vmov(T, Src0R);
2170 lowerAssign(InstAssign::create(Func, Dest, T));
2171 break;
2172 }
2173 case IceType_i64: {
2174 // t0, t1 <- src0
2175 // dest[31..0] = t0
2176 // dest[63..32] = t1
2177 assert(Src0->getType() == IceType_f64);
2178 Variable *T0 = makeReg(IceType_i32);
2179 Variable *T1 = makeReg(IceType_i32);
2180 Variable *Src0R = legalizeToReg(Src0);
John Portof977f712015-09-14 16:28:33 -07002181 _vmov(InstARM32Vmov::RegisterPair(T0, T1), Src0R);
Andrew Scull6d47bcd2015-09-17 17:10:05 -07002182 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
2183 lowerAssign(InstAssign::create(Func, Dest64On32->getLo(), T0));
2184 lowerAssign(InstAssign::create(Func, Dest64On32->getHi(), T1));
John Portof977f712015-09-14 16:28:33 -07002185 break;
2186 }
2187 case IceType_f64: {
2188 // T0 <- lo(src)
2189 // T1 <- hi(src)
2190 // vmov T2, T0, T1
2191 // Dest <- T2
2192 assert(Src0->getType() == IceType_i64);
2193 Variable *SrcLo = legalizeToReg(loOperand(Src0));
2194 Variable *SrcHi = legalizeToReg(hiOperand(Src0));
2195 Variable *T = makeReg(IceType_f64);
2196 _vmov(T, InstARM32Vmov::RegisterPair(SrcLo, SrcHi));
2197 lowerAssign(InstAssign::create(Func, Dest, T));
2198 break;
2199 }
2200 case IceType_v8i1:
2201 UnimplementedError(Func->getContext()->getFlags());
2202 break;
2203 case IceType_v16i1:
2204 UnimplementedError(Func->getContext()->getFlags());
2205 break;
2206 case IceType_v8i16:
2207 UnimplementedError(Func->getContext()->getFlags());
2208 break;
2209 case IceType_v16i8:
2210 UnimplementedError(Func->getContext()->getFlags());
2211 break;
2212 case IceType_v4i32:
John Porto385351b2015-09-16 16:11:10 -07002213 // avoid cryptic liveness errors
2214 Context.insert(InstFakeDef::create(Func, Dest));
John Portof977f712015-09-14 16:28:33 -07002215 UnimplementedError(Func->getContext()->getFlags());
2216 break;
2217 case IceType_v4f32:
2218 UnimplementedError(Func->getContext()->getFlags());
2219 break;
2220 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002221 break;
2222 }
2223 }
2224}
2225
2226void TargetARM32::lowerExtractElement(const InstExtractElement *Inst) {
2227 (void)Inst;
Jan Voungb2d50842015-05-12 09:53:50 -07002228 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002229}
2230
John Porto2f5534f2015-09-18 15:59:47 -07002231namespace {
2232// Validates FCMPARM32_TABLE's declaration w.r.t. InstFcmp::FCondition ordering
2233// (and naming).
2234enum {
2235#define X(val, CC0, CC1) _fcmp_ll_##val,
2236 FCMPARM32_TABLE
2237#undef X
2238 _fcmp_ll_NUM
2239};
2240
2241enum {
2242#define X(tag, str) _fcmp_hl_##tag = InstFcmp::tag,
2243 ICEINSTFCMP_TABLE
2244#undef X
2245 _fcmp_hl_NUM
2246};
2247
2248static_assert(_fcmp_hl_NUM == _fcmp_ll_NUM,
2249 "Inconsistency between high-level and low-level fcmp tags.");
2250#define X(tag, str) \
2251 static_assert( \
2252 _fcmp_hl_##tag == _fcmp_ll_##tag, \
2253 "Inconsistency between high-level and low-level fcmp tag " #tag);
2254ICEINSTFCMP_TABLE
2255#undef X
2256
2257struct {
2258 CondARM32::Cond CC0;
2259 CondARM32::Cond CC1;
2260} TableFcmp[] = {
2261#define X(val, CC0, CC1) \
2262 { CondARM32::CC0, CondARM32::CC1 } \
2263 ,
2264 FCMPARM32_TABLE
2265#undef X
2266};
2267} // end of anonymous namespace
2268
Jan Voungb36ad9b2015-04-21 17:01:49 -07002269void TargetARM32::lowerFcmp(const InstFcmp *Inst) {
John Porto2f5534f2015-09-18 15:59:47 -07002270 Variable *Dest = Inst->getDest();
2271 if (isVectorType(Dest->getType())) {
2272 UnimplementedError(Func->getContext()->getFlags());
2273 return;
2274 }
2275
2276 Variable *Src0R = legalizeToReg(Inst->getSrc(0));
2277 Variable *Src1R = legalizeToReg(Inst->getSrc(1));
2278 Variable *T = makeReg(IceType_i32);
2279 _vcmp(Src0R, Src1R);
2280 _mov(T, Ctx->getConstantZero(IceType_i32));
2281 _vmrs();
2282 Operand *One = Ctx->getConstantInt32(1);
2283 InstFcmp::FCond Condition = Inst->getCondition();
2284 assert(Condition < llvm::array_lengthof(TableFcmp));
2285 CondARM32::Cond CC0 = TableFcmp[Condition].CC0;
2286 CondARM32::Cond CC1 = TableFcmp[Condition].CC1;
2287 if (CC0 != CondARM32::kNone) {
2288 _mov(T, One, CC0);
2289 // If this mov is not a maybe mov, but an actual mov (i.e., CC0 == AL), we
2290 // don't want to set_dest_nonkillable so that liveness + dead-code
2291 // elimination will get rid of the previous assignment (i.e., T = 0) above.
2292 if (CC0 != CondARM32::AL)
2293 _set_dest_nonkillable();
2294 }
2295 if (CC1 != CondARM32::kNone) {
2296 assert(CC0 != CondARM32::kNone);
2297 assert(CC1 != CondARM32::AL);
2298 _mov_nonkillable(T, One, CC1);
2299 }
2300 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002301}
2302
2303void TargetARM32::lowerIcmp(const InstIcmp *Inst) {
Jan Voung3bfd99a2015-05-22 16:35:25 -07002304 Variable *Dest = Inst->getDest();
Jan Voungfbdd2442015-07-15 12:36:20 -07002305 Operand *Src0 = legalizeUndef(Inst->getSrc(0));
2306 Operand *Src1 = legalizeUndef(Inst->getSrc(1));
Jan Voung3bfd99a2015-05-22 16:35:25 -07002307
2308 if (isVectorType(Dest->getType())) {
2309 UnimplementedError(Func->getContext()->getFlags());
2310 return;
2311 }
2312
2313 // a=icmp cond, b, c ==>
2314 // GCC does:
2315 // cmp b.hi, c.hi or cmp b.lo, c.lo
2316 // cmp.eq b.lo, c.lo sbcs t1, b.hi, c.hi
2317 // mov.<C1> t, #1 mov.<C1> t, #1
2318 // mov.<C2> t, #0 mov.<C2> t, #0
2319 // mov a, t mov a, t
2320 // where the "cmp.eq b.lo, c.lo" is used for unsigned and "sbcs t1, hi, hi"
Andrew Scull57e12682015-09-16 11:30:19 -07002321 // is used for signed compares. In some cases, b and c need to be swapped as
2322 // well.
Jan Voung3bfd99a2015-05-22 16:35:25 -07002323 //
2324 // LLVM does:
2325 // for EQ and NE:
2326 // eor t1, b.hi, c.hi
2327 // eor t2, b.lo, c.hi
2328 // orrs t, t1, t2
2329 // mov.<C> t, #1
2330 // mov a, t
2331 //
Andrew Scull57e12682015-09-16 11:30:19 -07002332 // that's nice in that it's just as short but has fewer dependencies for
2333 // better ILP at the cost of more registers.
Jan Voung3bfd99a2015-05-22 16:35:25 -07002334 //
Andrew Scull57e12682015-09-16 11:30:19 -07002335 // Otherwise for signed/unsigned <, <=, etc. LLVM uses a sequence with two
2336 // unconditional mov #0, two cmps, two conditional mov #1, and one
2337 // conditional reg mov. That has few dependencies for good ILP, but is a
2338 // longer sequence.
Jan Voung3bfd99a2015-05-22 16:35:25 -07002339 //
2340 // So, we are going with the GCC version since it's usually better (except
2341 // perhaps for eq/ne). We could revisit special-casing eq/ne later.
2342 Constant *Zero = Ctx->getConstantZero(IceType_i32);
2343 Constant *One = Ctx->getConstantInt32(1);
2344 if (Src0->getType() == IceType_i64) {
2345 InstIcmp::ICond Conditon = Inst->getCondition();
2346 size_t Index = static_cast<size_t>(Conditon);
Andrew Scull2c688f62015-09-09 11:56:10 -07002347 assert(Index < llvm::array_lengthof(TableIcmp64));
Jan Voung3bfd99a2015-05-22 16:35:25 -07002348 Variable *Src0Lo, *Src0Hi;
2349 Operand *Src1LoRF, *Src1HiRF;
2350 if (TableIcmp64[Index].Swapped) {
Andrew Scull97f460d2015-07-21 10:07:42 -07002351 Src0Lo = legalizeToReg(loOperand(Src1));
2352 Src0Hi = legalizeToReg(hiOperand(Src1));
Jan Voung3bfd99a2015-05-22 16:35:25 -07002353 Src1LoRF = legalize(loOperand(Src0), Legal_Reg | Legal_Flex);
2354 Src1HiRF = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex);
2355 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07002356 Src0Lo = legalizeToReg(loOperand(Src0));
2357 Src0Hi = legalizeToReg(hiOperand(Src0));
Jan Voung3bfd99a2015-05-22 16:35:25 -07002358 Src1LoRF = legalize(loOperand(Src1), Legal_Reg | Legal_Flex);
2359 Src1HiRF = legalize(hiOperand(Src1), Legal_Reg | Legal_Flex);
2360 }
2361 Variable *T = makeReg(IceType_i32);
2362 if (TableIcmp64[Index].IsSigned) {
2363 Variable *ScratchReg = makeReg(IceType_i32);
2364 _cmp(Src0Lo, Src1LoRF);
2365 _sbcs(ScratchReg, Src0Hi, Src1HiRF);
Andrew Scull57e12682015-09-16 11:30:19 -07002366 // ScratchReg isn't going to be used, but we need the side-effect of
2367 // setting flags from this operation.
Jan Voung3bfd99a2015-05-22 16:35:25 -07002368 Context.insert(InstFakeUse::create(Func, ScratchReg));
2369 } else {
2370 _cmp(Src0Hi, Src1HiRF);
2371 _cmp(Src0Lo, Src1LoRF, CondARM32::EQ);
2372 }
2373 _mov(T, One, TableIcmp64[Index].C1);
2374 _mov_nonkillable(T, Zero, TableIcmp64[Index].C2);
2375 _mov(Dest, T);
2376 return;
2377 }
2378
2379 // a=icmp cond b, c ==>
2380 // GCC does:
2381 // <u/s>xtb tb, b
2382 // <u/s>xtb tc, c
2383 // cmp tb, tc
2384 // mov.C1 t, #0
2385 // mov.C2 t, #1
2386 // mov a, t
Andrew Scull57e12682015-09-16 11:30:19 -07002387 // where the unsigned/sign extension is not needed for 32-bit. They also have
2388 // special cases for EQ and NE. E.g., for NE:
Jan Voung3bfd99a2015-05-22 16:35:25 -07002389 // <extend to tb, tc>
2390 // subs t, tb, tc
2391 // movne t, #1
2392 // mov a, t
2393 //
2394 // LLVM does:
2395 // lsl tb, b, #<N>
2396 // mov t, #0
2397 // cmp tb, c, lsl #<N>
2398 // mov.<C> t, #1
2399 // mov a, t
2400 //
Andrew Scull57e12682015-09-16 11:30:19 -07002401 // the left shift is by 0, 16, or 24, which allows the comparison to focus on
2402 // the digits that actually matter (for 16-bit or 8-bit signed/unsigned). For
2403 // the unsigned case, for some reason it does similar to GCC and does a uxtb
2404 // first. It's not clear to me why that special-casing is needed.
Jan Voung3bfd99a2015-05-22 16:35:25 -07002405 //
Andrew Scull57e12682015-09-16 11:30:19 -07002406 // We'll go with the LLVM way for now, since it's shorter and has just as few
2407 // dependencies.
Jan Voung66c3d5e2015-06-04 17:02:31 -07002408 int32_t ShiftAmt = 32 - getScalarIntBitWidth(Src0->getType());
2409 assert(ShiftAmt >= 0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002410 Constant *ShiftConst = nullptr;
2411 Variable *Src0R = nullptr;
2412 Variable *T = makeReg(IceType_i32);
Jan Voung66c3d5e2015-06-04 17:02:31 -07002413 if (ShiftAmt) {
2414 ShiftConst = Ctx->getConstantInt32(ShiftAmt);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002415 Src0R = makeReg(IceType_i32);
Andrew Scull97f460d2015-07-21 10:07:42 -07002416 _lsl(Src0R, legalizeToReg(Src0), ShiftConst);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002417 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07002418 Src0R = legalizeToReg(Src0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002419 }
2420 _mov(T, Zero);
Jan Voung66c3d5e2015-06-04 17:02:31 -07002421 if (ShiftAmt) {
Andrew Scull97f460d2015-07-21 10:07:42 -07002422 Variable *Src1R = legalizeToReg(Src1);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002423 OperandARM32FlexReg *Src1RShifted = OperandARM32FlexReg::create(
2424 Func, IceType_i32, Src1R, OperandARM32::LSL, ShiftConst);
2425 _cmp(Src0R, Src1RShifted);
2426 } else {
2427 Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
2428 _cmp(Src0R, Src1RF);
2429 }
2430 _mov_nonkillable(T, One, getIcmp32Mapping(Inst->getCondition()));
2431 _mov(Dest, T);
2432 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07002433}
2434
2435void TargetARM32::lowerInsertElement(const InstInsertElement *Inst) {
2436 (void)Inst;
Jan Voungb2d50842015-05-12 09:53:50 -07002437 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002438}
2439
2440void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Jim Stichnotha8d47132015-09-08 14:43:38 -07002441 switch (Instr->getIntrinsicInfo().ID) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07002442 case Intrinsics::AtomicCmpxchg: {
Jan Voungb2d50842015-05-12 09:53:50 -07002443 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002444 return;
2445 }
2446 case Intrinsics::AtomicFence:
Jan Voungb2d50842015-05-12 09:53:50 -07002447 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002448 return;
2449 case Intrinsics::AtomicFenceAll:
Andrew Scull57e12682015-09-16 11:30:19 -07002450 // NOTE: FenceAll should prevent and load/store from being moved across the
2451 // fence (both atomic and non-atomic). The InstARM32Mfence instruction is
2452 // currently marked coarsely as "HasSideEffects".
Jan Voungb2d50842015-05-12 09:53:50 -07002453 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002454 return;
2455 case Intrinsics::AtomicIsLockFree: {
Jan Voungb2d50842015-05-12 09:53:50 -07002456 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002457 return;
2458 }
2459 case Intrinsics::AtomicLoad: {
Jan Voungb2d50842015-05-12 09:53:50 -07002460 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002461 return;
2462 }
2463 case Intrinsics::AtomicRMW:
Jan Voungb2d50842015-05-12 09:53:50 -07002464 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002465 return;
2466 case Intrinsics::AtomicStore: {
Jan Voungb2d50842015-05-12 09:53:50 -07002467 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002468 return;
2469 }
2470 case Intrinsics::Bswap: {
Jan Voungf645d852015-07-09 10:35:09 -07002471 Variable *Dest = Instr->getDest();
2472 Operand *Val = Instr->getArg(0);
2473 Type Ty = Val->getType();
2474 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002475 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07002476 Variable *Val_Lo = legalizeToReg(loOperand(Val));
2477 Variable *Val_Hi = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07002478 Variable *T_Lo = makeReg(IceType_i32);
2479 Variable *T_Hi = makeReg(IceType_i32);
2480 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
2481 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2482 _rev(T_Lo, Val_Lo);
2483 _rev(T_Hi, Val_Hi);
2484 _mov(DestLo, T_Hi);
2485 _mov(DestHi, T_Lo);
2486 } else {
2487 assert(Ty == IceType_i32 || Ty == IceType_i16);
Andrew Scull97f460d2015-07-21 10:07:42 -07002488 Variable *ValR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07002489 Variable *T = makeReg(Ty);
2490 _rev(T, ValR);
2491 if (Val->getType() == IceType_i16) {
2492 Operand *Sixteen =
2493 legalize(Ctx->getConstantInt32(16), Legal_Reg | Legal_Flex);
2494 _lsr(T, T, Sixteen);
2495 }
2496 _mov(Dest, T);
2497 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002498 return;
2499 }
2500 case Intrinsics::Ctpop: {
Jan Voungf645d852015-07-09 10:35:09 -07002501 Variable *Dest = Instr->getDest();
2502 Operand *Val = Instr->getArg(0);
2503 InstCall *Call = makeHelperCall(isInt32Asserting32Or64(Val->getType())
2504 ? H_call_ctpop_i32
2505 : H_call_ctpop_i64,
2506 Dest, 1);
2507 Call->addArg(Val);
2508 lowerCall(Call);
2509 // The popcount helpers always return 32-bit values, while the intrinsic's
Andrew Scull57e12682015-09-16 11:30:19 -07002510 // signature matches some 64-bit platform's native instructions and expect
2511 // to fill a 64-bit reg. Thus, clear the upper bits of the dest just in
2512 // case the user doesn't do that in the IR or doesn't toss the bits via
2513 // truncate.
Jan Voungf645d852015-07-09 10:35:09 -07002514 if (Val->getType() == IceType_i64) {
2515 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2516 Constant *Zero = Ctx->getConstantZero(IceType_i32);
Jan Voung28068ad2015-07-31 12:58:46 -07002517 Variable *T = nullptr;
2518 _mov(T, Zero);
2519 _mov(DestHi, T);
Jan Voungf645d852015-07-09 10:35:09 -07002520 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002521 return;
2522 }
2523 case Intrinsics::Ctlz: {
Andrew Scull57e12682015-09-16 11:30:19 -07002524 // The "is zero undef" parameter is ignored and we always return a
2525 // well-defined value.
Jan Voungf645d852015-07-09 10:35:09 -07002526 Operand *Val = Instr->getArg(0);
2527 Variable *ValLoR;
2528 Variable *ValHiR = nullptr;
2529 if (Val->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002530 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07002531 ValLoR = legalizeToReg(loOperand(Val));
2532 ValHiR = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07002533 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07002534 ValLoR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07002535 }
2536 lowerCLZ(Instr->getDest(), ValLoR, ValHiR);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002537 return;
2538 }
2539 case Intrinsics::Cttz: {
Jan Voungf645d852015-07-09 10:35:09 -07002540 // Essentially like Clz, but reverse the bits first.
2541 Operand *Val = Instr->getArg(0);
2542 Variable *ValLoR;
2543 Variable *ValHiR = nullptr;
2544 if (Val->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002545 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07002546 ValLoR = legalizeToReg(loOperand(Val));
2547 ValHiR = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07002548 Variable *TLo = makeReg(IceType_i32);
2549 Variable *THi = makeReg(IceType_i32);
2550 _rbit(TLo, ValLoR);
2551 _rbit(THi, ValHiR);
2552 ValLoR = THi;
2553 ValHiR = TLo;
2554 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07002555 ValLoR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07002556 Variable *T = makeReg(IceType_i32);
2557 _rbit(T, ValLoR);
2558 ValLoR = T;
2559 }
2560 lowerCLZ(Instr->getDest(), ValLoR, ValHiR);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002561 return;
2562 }
2563 case Intrinsics::Fabs: {
Jan Voung86ebec12015-08-09 07:58:35 -07002564 // Add a fake def to keep liveness consistent in the meantime.
2565 Context.insert(InstFakeDef::create(Func, Instr->getDest()));
Jan Voungb2d50842015-05-12 09:53:50 -07002566 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002567 return;
2568 }
2569 case Intrinsics::Longjmp: {
2570 InstCall *Call = makeHelperCall(H_call_longjmp, nullptr, 2);
2571 Call->addArg(Instr->getArg(0));
2572 Call->addArg(Instr->getArg(1));
2573 lowerCall(Call);
2574 return;
2575 }
2576 case Intrinsics::Memcpy: {
2577 // In the future, we could potentially emit an inline memcpy/memset, etc.
2578 // for intrinsic calls w/ a known length.
2579 InstCall *Call = makeHelperCall(H_call_memcpy, nullptr, 3);
2580 Call->addArg(Instr->getArg(0));
2581 Call->addArg(Instr->getArg(1));
2582 Call->addArg(Instr->getArg(2));
2583 lowerCall(Call);
2584 return;
2585 }
2586 case Intrinsics::Memmove: {
2587 InstCall *Call = makeHelperCall(H_call_memmove, nullptr, 3);
2588 Call->addArg(Instr->getArg(0));
2589 Call->addArg(Instr->getArg(1));
2590 Call->addArg(Instr->getArg(2));
2591 lowerCall(Call);
2592 return;
2593 }
2594 case Intrinsics::Memset: {
Jan Voungf645d852015-07-09 10:35:09 -07002595 // The value operand needs to be extended to a stack slot size because the
2596 // PNaCl ABI requires arguments to be at least 32 bits wide.
Jan Voungb36ad9b2015-04-21 17:01:49 -07002597 Operand *ValOp = Instr->getArg(1);
2598 assert(ValOp->getType() == IceType_i8);
2599 Variable *ValExt = Func->makeVariable(stackSlotType());
2600 lowerCast(InstCast::create(Func, InstCast::Zext, ValExt, ValOp));
Jan Voungf645d852015-07-09 10:35:09 -07002601 // Technically, ARM has their own __aeabi_memset, but we can use plain
2602 // memset too. The value and size argument need to be flipped if we ever
2603 // decide to use __aeabi_memset.
Jan Voungb36ad9b2015-04-21 17:01:49 -07002604 InstCall *Call = makeHelperCall(H_call_memset, nullptr, 3);
2605 Call->addArg(Instr->getArg(0));
2606 Call->addArg(ValExt);
2607 Call->addArg(Instr->getArg(2));
2608 lowerCall(Call);
2609 return;
2610 }
2611 case Intrinsics::NaClReadTP: {
2612 if (Ctx->getFlags().getUseSandboxing()) {
Jan Voungb2d50842015-05-12 09:53:50 -07002613 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002614 } else {
2615 InstCall *Call = makeHelperCall(H_call_read_tp, Instr->getDest(), 0);
2616 lowerCall(Call);
2617 }
2618 return;
2619 }
2620 case Intrinsics::Setjmp: {
2621 InstCall *Call = makeHelperCall(H_call_setjmp, Instr->getDest(), 1);
2622 Call->addArg(Instr->getArg(0));
2623 lowerCall(Call);
2624 return;
2625 }
2626 case Intrinsics::Sqrt: {
Jan Voung86ebec12015-08-09 07:58:35 -07002627 Variable *Src = legalizeToReg(Instr->getArg(0));
2628 Variable *Dest = Instr->getDest();
2629 Variable *T = makeReg(Dest->getType());
2630 _vsqrt(T, Src);
2631 _vmov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002632 return;
2633 }
2634 case Intrinsics::Stacksave: {
Jan Voungf645d852015-07-09 10:35:09 -07002635 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
2636 Variable *Dest = Instr->getDest();
2637 _mov(Dest, SP);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002638 return;
2639 }
2640 case Intrinsics::Stackrestore: {
Jan Voungf645d852015-07-09 10:35:09 -07002641 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
2642 Operand *Val = legalize(Instr->getArg(0), Legal_Reg | Legal_Flex);
2643 _mov_nonkillable(SP, Val);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002644 return;
2645 }
2646 case Intrinsics::Trap:
Jan Voungf645d852015-07-09 10:35:09 -07002647 _trap();
Jan Voungb36ad9b2015-04-21 17:01:49 -07002648 return;
2649 case Intrinsics::UnknownIntrinsic:
2650 Func->setError("Should not be lowering UnknownIntrinsic");
2651 return;
2652 }
2653 return;
2654}
2655
Jan Voungf645d852015-07-09 10:35:09 -07002656void TargetARM32::lowerCLZ(Variable *Dest, Variable *ValLoR, Variable *ValHiR) {
2657 Type Ty = Dest->getType();
2658 assert(Ty == IceType_i32 || Ty == IceType_i64);
2659 Variable *T = makeReg(IceType_i32);
2660 _clz(T, ValLoR);
2661 if (Ty == IceType_i64) {
2662 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
2663 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2664 Operand *Zero =
2665 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
2666 Operand *ThirtyTwo =
2667 legalize(Ctx->getConstantInt32(32), Legal_Reg | Legal_Flex);
2668 _cmp(ValHiR, Zero);
2669 Variable *T2 = makeReg(IceType_i32);
2670 _add(T2, T, ThirtyTwo);
2671 _clz(T2, ValHiR, CondARM32::NE);
Andrew Scull57e12682015-09-16 11:30:19 -07002672 // T2 is actually a source as well when the predicate is not AL (since it
2673 // may leave T2 alone). We use set_dest_nonkillable to prolong the liveness
2674 // of T2 as if it was used as a source.
Jan Voungf645d852015-07-09 10:35:09 -07002675 _set_dest_nonkillable();
2676 _mov(DestLo, T2);
Jan Voung28068ad2015-07-31 12:58:46 -07002677 Variable *T3 = nullptr;
2678 _mov(T3, Zero);
2679 _mov(DestHi, T3);
Jan Voungf645d852015-07-09 10:35:09 -07002680 return;
2681 }
2682 _mov(Dest, T);
2683 return;
2684}
2685
Jan Voungbefd03a2015-06-02 11:03:03 -07002686void TargetARM32::lowerLoad(const InstLoad *Load) {
Andrew Scull57e12682015-09-16 11:30:19 -07002687 // A Load instruction can be treated the same as an Assign instruction, after
2688 // the source operand is transformed into an OperandARM32Mem operand.
Jan Voungbefd03a2015-06-02 11:03:03 -07002689 Type Ty = Load->getDest()->getType();
2690 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
2691 Variable *DestLoad = Load->getDest();
2692
Andrew Scull57e12682015-09-16 11:30:19 -07002693 // TODO(jvoung): handled folding opportunities. Sign and zero extension can
2694 // be folded into a load.
Jan Voungbefd03a2015-06-02 11:03:03 -07002695 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0);
2696 lowerAssign(Assign);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002697}
2698
2699void TargetARM32::doAddressOptLoad() {
Jan Voungb2d50842015-05-12 09:53:50 -07002700 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002701}
2702
Qining Luaee5fa82015-08-20 14:59:03 -07002703void TargetARM32::randomlyInsertNop(float Probability,
2704 RandomNumberGenerator &RNG) {
2705 RandomNumberGeneratorWrapper RNGW(RNG);
2706 if (RNGW.getTrueWithProbability(Probability)) {
Jan Voungb2d50842015-05-12 09:53:50 -07002707 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002708 }
2709}
2710
2711void TargetARM32::lowerPhi(const InstPhi * /*Inst*/) {
2712 Func->setError("Phi found in regular instruction list");
2713}
2714
2715void TargetARM32::lowerRet(const InstRet *Inst) {
Jan Voungb2d50842015-05-12 09:53:50 -07002716 Variable *Reg = nullptr;
2717 if (Inst->hasRetValue()) {
Jan Voungb3401d22015-05-18 09:38:21 -07002718 Operand *Src0 = Inst->getRetValue();
Jan Voung86ebec12015-08-09 07:58:35 -07002719 Type Ty = Src0->getType();
2720 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002721 Src0 = legalizeUndef(Src0);
Andrew Scull97f460d2015-07-21 10:07:42 -07002722 Variable *R0 = legalizeToReg(loOperand(Src0), RegARM32::Reg_r0);
2723 Variable *R1 = legalizeToReg(hiOperand(Src0), RegARM32::Reg_r1);
Jan Voungb3401d22015-05-18 09:38:21 -07002724 Reg = R0;
2725 Context.insert(InstFakeUse::create(Func, R1));
Jan Voung86ebec12015-08-09 07:58:35 -07002726 } else if (Ty == IceType_f32) {
2727 Variable *S0 = legalizeToReg(Src0, RegARM32::Reg_s0);
2728 Reg = S0;
2729 } else if (Ty == IceType_f64) {
2730 Variable *D0 = legalizeToReg(Src0, RegARM32::Reg_d0);
2731 Reg = D0;
Jan Voungb3401d22015-05-18 09:38:21 -07002732 } else if (isVectorType(Src0->getType())) {
Jan Voung86ebec12015-08-09 07:58:35 -07002733 Variable *Q0 = legalizeToReg(Src0, RegARM32::Reg_q0);
2734 Reg = Q0;
Jan Voungb3401d22015-05-18 09:38:21 -07002735 } else {
2736 Operand *Src0F = legalize(Src0, Legal_Reg | Legal_Flex);
Jan Voung3bfd99a2015-05-22 16:35:25 -07002737 _mov(Reg, Src0F, CondARM32::AL, RegARM32::Reg_r0);
Jan Voungb3401d22015-05-18 09:38:21 -07002738 }
Jan Voungb2d50842015-05-12 09:53:50 -07002739 }
Andrew Scull57e12682015-09-16 11:30:19 -07002740 // Add a ret instruction even if sandboxing is enabled, because addEpilog
2741 // explicitly looks for a ret instruction as a marker for where to insert the
2742 // frame removal instructions. addEpilog is responsible for restoring the
2743 // "lr" register as needed prior to this ret instruction.
Jan Voungb2d50842015-05-12 09:53:50 -07002744 _ret(getPhysicalRegister(RegARM32::Reg_lr), Reg);
Andrew Scull57e12682015-09-16 11:30:19 -07002745 // Add a fake use of sp to make sure sp stays alive for the entire function.
2746 // Otherwise post-call sp adjustments get dead-code eliminated.
2747 // TODO: Are there more places where the fake use should be inserted? E.g.
2748 // "void f(int n){while(1) g(n);}" may not have a ret instruction.
Jan Voungf645d852015-07-09 10:35:09 -07002749 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
Jan Voungb2d50842015-05-12 09:53:50 -07002750 Context.insert(InstFakeUse::create(Func, SP));
Jan Voungb36ad9b2015-04-21 17:01:49 -07002751}
2752
2753void TargetARM32::lowerSelect(const InstSelect *Inst) {
Jan Vounge0df91f2015-06-30 08:47:06 -07002754 Variable *Dest = Inst->getDest();
2755 Type DestTy = Dest->getType();
2756 Operand *SrcT = Inst->getTrueOperand();
2757 Operand *SrcF = Inst->getFalseOperand();
2758 Operand *Condition = Inst->getCondition();
2759
2760 if (isVectorType(DestTy)) {
2761 UnimplementedError(Func->getContext()->getFlags());
2762 return;
2763 }
Jan Vounge0df91f2015-06-30 08:47:06 -07002764 // TODO(jvoung): handle folding opportunities.
2765 // cmp cond, #0; mov t, SrcF; mov_cond t, SrcT; mov dest, t
Andrew Scull97f460d2015-07-21 10:07:42 -07002766 Variable *CmpOpnd0 = legalizeToReg(Condition);
Jan Vounge0df91f2015-06-30 08:47:06 -07002767 Operand *CmpOpnd1 = Ctx->getConstantZero(IceType_i32);
2768 _cmp(CmpOpnd0, CmpOpnd1);
John Porto2f5534f2015-09-18 15:59:47 -07002769 static constexpr CondARM32::Cond Cond = CondARM32::NE;
Jan Vounge0df91f2015-06-30 08:47:06 -07002770 if (DestTy == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002771 SrcT = legalizeUndef(SrcT);
2772 SrcF = legalizeUndef(SrcF);
Jan Vounge0df91f2015-06-30 08:47:06 -07002773 // Set the low portion.
2774 Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
2775 Variable *TLo = nullptr;
2776 Operand *SrcFLo = legalize(loOperand(SrcF), Legal_Reg | Legal_Flex);
2777 _mov(TLo, SrcFLo);
2778 Operand *SrcTLo = legalize(loOperand(SrcT), Legal_Reg | Legal_Flex);
2779 _mov_nonkillable(TLo, SrcTLo, Cond);
2780 _mov(DestLo, TLo);
2781 // Set the high portion.
2782 Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
2783 Variable *THi = nullptr;
2784 Operand *SrcFHi = legalize(hiOperand(SrcF), Legal_Reg | Legal_Flex);
2785 _mov(THi, SrcFHi);
2786 Operand *SrcTHi = legalize(hiOperand(SrcT), Legal_Reg | Legal_Flex);
2787 _mov_nonkillable(THi, SrcTHi, Cond);
2788 _mov(DestHi, THi);
2789 return;
2790 }
John Porto2f5534f2015-09-18 15:59:47 -07002791
2792 if (isFloatingType(DestTy)) {
2793 Variable *T = makeReg(DestTy);
2794 SrcF = legalizeToReg(SrcF);
2795 assert(DestTy == SrcF->getType());
2796 _vmov(T, SrcF);
2797 SrcT = legalizeToReg(SrcT);
2798 assert(DestTy == SrcT->getType());
2799 _vmov(T, SrcT, Cond);
2800 _set_dest_nonkillable();
2801 _vmov(Dest, T);
2802 return;
2803 }
2804
Jan Vounge0df91f2015-06-30 08:47:06 -07002805 Variable *T = nullptr;
2806 SrcF = legalize(SrcF, Legal_Reg | Legal_Flex);
2807 _mov(T, SrcF);
2808 SrcT = legalize(SrcT, Legal_Reg | Legal_Flex);
2809 _mov_nonkillable(T, SrcT, Cond);
2810 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002811}
2812
2813void TargetARM32::lowerStore(const InstStore *Inst) {
Jan Voungbefd03a2015-06-02 11:03:03 -07002814 Operand *Value = Inst->getData();
2815 Operand *Addr = Inst->getAddr();
2816 OperandARM32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
2817 Type Ty = NewAddr->getType();
2818
2819 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002820 Value = legalizeUndef(Value);
Andrew Scull97f460d2015-07-21 10:07:42 -07002821 Variable *ValueHi = legalizeToReg(hiOperand(Value));
2822 Variable *ValueLo = legalizeToReg(loOperand(Value));
Jan Voungbefd03a2015-06-02 11:03:03 -07002823 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr)));
2824 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr)));
Jan Voungbefd03a2015-06-02 11:03:03 -07002825 } else {
John Porto385351b2015-09-16 16:11:10 -07002826 if (isVectorType(Ty)) {
2827 UnimplementedError(Func->getContext()->getFlags());
2828 }
Andrew Scull97f460d2015-07-21 10:07:42 -07002829 Variable *ValueR = legalizeToReg(Value);
Jan Voungbefd03a2015-06-02 11:03:03 -07002830 _str(ValueR, NewAddr);
2831 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002832}
2833
2834void TargetARM32::doAddressOptStore() {
Jan Voungb2d50842015-05-12 09:53:50 -07002835 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002836}
2837
2838void TargetARM32::lowerSwitch(const InstSwitch *Inst) {
Andrew Scullfdc54db2015-06-29 11:21:18 -07002839 // This implements the most naive possible lowering.
2840 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
2841 Operand *Src0 = Inst->getComparison();
2842 SizeT NumCases = Inst->getNumCases();
2843 if (Src0->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002844 Src0 = legalizeUndef(Src0);
Andrew Scull97f460d2015-07-21 10:07:42 -07002845 Variable *Src0Lo = legalizeToReg(loOperand(Src0));
2846 Variable *Src0Hi = legalizeToReg(hiOperand(Src0));
Andrew Scullfdc54db2015-06-29 11:21:18 -07002847 for (SizeT I = 0; I < NumCases; ++I) {
2848 Operand *ValueLo = Ctx->getConstantInt32(Inst->getValue(I));
2849 Operand *ValueHi = Ctx->getConstantInt32(Inst->getValue(I) >> 32);
2850 ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex);
2851 ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex);
2852 _cmp(Src0Lo, ValueLo);
2853 _cmp(Src0Hi, ValueHi, CondARM32::EQ);
2854 _br(Inst->getLabel(I), CondARM32::EQ);
2855 }
2856 _br(Inst->getLabelDefault());
2857 return;
2858 }
Jan Vounge0df91f2015-06-30 08:47:06 -07002859
Andrew Scullfdc54db2015-06-29 11:21:18 -07002860 // 32 bit integer
Andrew Scull97f460d2015-07-21 10:07:42 -07002861 Variable *Src0Var = legalizeToReg(Src0);
Andrew Scullfdc54db2015-06-29 11:21:18 -07002862 for (SizeT I = 0; I < NumCases; ++I) {
2863 Operand *Value = Ctx->getConstantInt32(Inst->getValue(I));
2864 Value = legalize(Value, Legal_Reg | Legal_Flex);
2865 _cmp(Src0Var, Value);
2866 _br(Inst->getLabel(I), CondARM32::EQ);
2867 }
2868 _br(Inst->getLabelDefault());
Jan Voungb36ad9b2015-04-21 17:01:49 -07002869}
2870
2871void TargetARM32::lowerUnreachable(const InstUnreachable * /*Inst*/) {
Jan Voung6ec369e2015-06-30 11:03:15 -07002872 _trap();
Jan Voungb36ad9b2015-04-21 17:01:49 -07002873}
2874
Jan Voungb36ad9b2015-04-21 17:01:49 -07002875void TargetARM32::prelowerPhis() {
Jan Voung53483692015-07-16 10:47:46 -07002876 PhiLowering::prelowerPhis32Bit<TargetARM32>(this, Context.getNode(), Func);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002877}
2878
Jan Voungb3401d22015-05-18 09:38:21 -07002879Variable *TargetARM32::makeVectorOfZeros(Type Ty, int32_t RegNum) {
2880 Variable *Reg = makeReg(Ty, RegNum);
2881 UnimplementedError(Func->getContext()->getFlags());
2882 return Reg;
2883}
2884
2885// Helper for legalize() to emit the right code to lower an operand to a
2886// register of the appropriate type.
2887Variable *TargetARM32::copyToReg(Operand *Src, int32_t RegNum) {
2888 Type Ty = Src->getType();
2889 Variable *Reg = makeReg(Ty, RegNum);
John Porto385351b2015-09-16 16:11:10 -07002890 if (isVectorType(Ty)) {
2891 // TODO(jpp): Src must be a register, or an address with base register.
2892 _vmov(Reg, Src);
2893 } else if (isFloatingType(Ty)) {
Jan Voung86ebec12015-08-09 07:58:35 -07002894 _vmov(Reg, Src);
Jan Voungb3401d22015-05-18 09:38:21 -07002895 } else {
Andrew Scull57e12682015-09-16 11:30:19 -07002896 // Mov's Src operand can really only be the flexible second operand type or
2897 // a register. Users should guarantee that.
Jan Voungb3401d22015-05-18 09:38:21 -07002898 _mov(Reg, Src);
2899 }
2900 return Reg;
2901}
2902
2903Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
2904 int32_t RegNum) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002905 Type Ty = From->getType();
Andrew Scull57e12682015-09-16 11:30:19 -07002906 // Assert that a physical register is allowed. To date, all calls to
2907 // legalize() allow a physical register. Legal_Flex converts registers to the
2908 // right type OperandARM32FlexReg as needed.
Jan Voungb3401d22015-05-18 09:38:21 -07002909 assert(Allowed & Legal_Reg);
Andrew Scull57e12682015-09-16 11:30:19 -07002910 // Go through the various types of operands: OperandARM32Mem,
2911 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if
2912 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we
2913 // can always copy to a register.
Jan Voungb3401d22015-05-18 09:38:21 -07002914 if (auto Mem = llvm::dyn_cast<OperandARM32Mem>(From)) {
Andrew Scull57e12682015-09-16 11:30:19 -07002915 // Before doing anything with a Mem operand, we need to ensure that the
2916 // Base and Index components are in physical registers.
Jan Voungb3401d22015-05-18 09:38:21 -07002917 Variable *Base = Mem->getBase();
2918 Variable *Index = Mem->getIndex();
2919 Variable *RegBase = nullptr;
2920 Variable *RegIndex = nullptr;
2921 if (Base) {
Andrew Scull97f460d2015-07-21 10:07:42 -07002922 RegBase = legalizeToReg(Base);
Jan Voungb3401d22015-05-18 09:38:21 -07002923 }
2924 if (Index) {
Andrew Scull97f460d2015-07-21 10:07:42 -07002925 RegIndex = legalizeToReg(Index);
Jan Voungb3401d22015-05-18 09:38:21 -07002926 }
2927 // Create a new operand if there was a change.
2928 if (Base != RegBase || Index != RegIndex) {
2929 // There is only a reg +/- reg or reg + imm form.
2930 // Figure out which to re-create.
2931 if (Mem->isRegReg()) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002932 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex,
Jan Voungb3401d22015-05-18 09:38:21 -07002933 Mem->getShiftOp(), Mem->getShiftAmt(),
2934 Mem->getAddrMode());
2935 } else {
Jan Voungfbdd2442015-07-15 12:36:20 -07002936 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Mem->getOffset(),
2937 Mem->getAddrMode());
Jan Voungb3401d22015-05-18 09:38:21 -07002938 }
2939 }
2940 if (!(Allowed & Legal_Mem)) {
Jan Voungb3401d22015-05-18 09:38:21 -07002941 Variable *Reg = makeReg(Ty, RegNum);
Jan Voung86ebec12015-08-09 07:58:35 -07002942 if (isVectorType(Ty)) {
2943 UnimplementedError(Func->getContext()->getFlags());
2944 } else if (isFloatingType(Ty)) {
2945 _vldr(Reg, Mem);
2946 } else {
2947 _ldr(Reg, Mem);
2948 }
Jan Voungb3401d22015-05-18 09:38:21 -07002949 From = Reg;
2950 } else {
2951 From = Mem;
2952 }
2953 return From;
2954 }
2955
2956 if (auto Flex = llvm::dyn_cast<OperandARM32Flex>(From)) {
2957 if (!(Allowed & Legal_Flex)) {
2958 if (auto FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) {
2959 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) {
2960 From = FlexReg->getReg();
Andrew Scull57e12682015-09-16 11:30:19 -07002961 // Fall through and let From be checked as a Variable below, where it
2962 // may or may not need a register.
Jan Voungb3401d22015-05-18 09:38:21 -07002963 } else {
2964 return copyToReg(Flex, RegNum);
2965 }
2966 } else {
2967 return copyToReg(Flex, RegNum);
2968 }
2969 } else {
2970 return From;
2971 }
2972 }
2973
2974 if (llvm::isa<Constant>(From)) {
2975 if (llvm::isa<ConstantUndef>(From)) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002976 From = legalizeUndef(From, RegNum);
2977 if (isVectorType(Ty))
2978 return From;
Jan Voungb3401d22015-05-18 09:38:21 -07002979 }
2980 // There should be no constants of vector type (other than undef).
Jan Voungfbdd2442015-07-15 12:36:20 -07002981 assert(!isVectorType(Ty));
Jan Voungb3401d22015-05-18 09:38:21 -07002982 bool CanBeFlex = Allowed & Legal_Flex;
Jan Voungfbdd2442015-07-15 12:36:20 -07002983 if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
Jan Voungb3401d22015-05-18 09:38:21 -07002984 uint32_t RotateAmt;
2985 uint32_t Immed_8;
2986 uint32_t Value = static_cast<uint32_t>(C32->getValue());
Andrew Scull57e12682015-09-16 11:30:19 -07002987 // Check if the immediate will fit in a Flexible second operand, if a
2988 // Flexible second operand is allowed. We need to know the exact value,
2989 // so that rules out relocatable constants. Also try the inverse and use
2990 // MVN if possible.
Jan Voungb3401d22015-05-18 09:38:21 -07002991 if (CanBeFlex &&
2992 OperandARM32FlexImm::canHoldImm(Value, &RotateAmt, &Immed_8)) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002993 return OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
Jan Voungb3401d22015-05-18 09:38:21 -07002994 } else if (CanBeFlex && OperandARM32FlexImm::canHoldImm(
2995 ~Value, &RotateAmt, &Immed_8)) {
Jan Voungfbdd2442015-07-15 12:36:20 -07002996 auto InvertedFlex =
2997 OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
Jan Voungb3401d22015-05-18 09:38:21 -07002998 Variable *Reg = makeReg(Ty, RegNum);
2999 _mvn(Reg, InvertedFlex);
3000 return Reg;
3001 } else {
3002 // Do a movw/movt to a register.
Jan Voungb3401d22015-05-18 09:38:21 -07003003 Variable *Reg = makeReg(Ty, RegNum);
3004 uint32_t UpperBits = (Value >> 16) & 0xFFFF;
3005 _movw(Reg,
3006 UpperBits != 0 ? Ctx->getConstantInt32(Value & 0xFFFF) : C32);
3007 if (UpperBits != 0) {
3008 _movt(Reg, Ctx->getConstantInt32(UpperBits));
3009 }
3010 return Reg;
3011 }
Jan Voungfbdd2442015-07-15 12:36:20 -07003012 } else if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
Jan Voungb3401d22015-05-18 09:38:21 -07003013 Variable *Reg = makeReg(Ty, RegNum);
3014 _movw(Reg, C);
3015 _movt(Reg, C);
3016 return Reg;
3017 } else {
Jan Voung86ebec12015-08-09 07:58:35 -07003018 assert(isScalarFloatingType(Ty));
Jan Voungb3401d22015-05-18 09:38:21 -07003019 // Load floats/doubles from literal pool.
Andrew Scull57e12682015-09-16 11:30:19 -07003020 // TODO(jvoung): Allow certain immediates to be encoded directly in an
3021 // operand. See Table A7-18 of the ARM manual: "Floating-point modified
3022 // immediate constants". Or, for 32-bit floating point numbers, just
3023 // encode the raw bits into a movw/movt pair to GPR, and vmov to an SREG,
3024 // instead of using a movw/movt pair to get the const-pool address then
3025 // loading to SREG.
Jan Voung86ebec12015-08-09 07:58:35 -07003026 std::string Buffer;
3027 llvm::raw_string_ostream StrBuf(Buffer);
3028 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf);
3029 llvm::cast<Constant>(From)->setShouldBePooled(true);
3030 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true);
3031 Variable *BaseReg = makeReg(getPointerType());
3032 _movw(BaseReg, Offset);
3033 _movt(BaseReg, Offset);
3034 From = formMemoryOperand(BaseReg, Ty);
3035 return copyToReg(From, RegNum);
Jan Voungb3401d22015-05-18 09:38:21 -07003036 }
Jan Voungb3401d22015-05-18 09:38:21 -07003037 }
3038
3039 if (auto Var = llvm::dyn_cast<Variable>(From)) {
Andrew Scull57e12682015-09-16 11:30:19 -07003040 // Check if the variable is guaranteed a physical register. This can happen
3041 // either when the variable is pre-colored or when it is assigned infinite
3042 // weight.
Andrew Scull11c9a322015-08-28 14:24:14 -07003043 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
Jan Voungb3401d22015-05-18 09:38:21 -07003044 // We need a new physical register for the operand if:
3045 // Mem is not allowed and Var isn't guaranteed a physical
3046 // register, or
3047 // RegNum is required and Var->getRegNum() doesn't match.
3048 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
3049 (RegNum != Variable::NoRegister && RegNum != Var->getRegNum())) {
3050 From = copyToReg(From, RegNum);
3051 }
3052 return From;
3053 }
3054 llvm_unreachable("Unhandled operand kind in legalize()");
3055
3056 return From;
3057}
3058
Jan Voungfbdd2442015-07-15 12:36:20 -07003059/// Provide a trivial wrapper to legalize() for this common usage.
Andrew Scull97f460d2015-07-21 10:07:42 -07003060Variable *TargetARM32::legalizeToReg(Operand *From, int32_t RegNum) {
Jan Voungb3401d22015-05-18 09:38:21 -07003061 return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
3062}
3063
Jan Voungfbdd2442015-07-15 12:36:20 -07003064/// Legalize undef values to concrete values.
3065Operand *TargetARM32::legalizeUndef(Operand *From, int32_t RegNum) {
3066 Type Ty = From->getType();
3067 if (llvm::isa<ConstantUndef>(From)) {
Andrew Scull57e12682015-09-16 11:30:19 -07003068 // Lower undefs to zero. Another option is to lower undefs to an
3069 // uninitialized register; however, using an uninitialized register results
3070 // in less predictable code.
Jan Voungfbdd2442015-07-15 12:36:20 -07003071 //
Andrew Scull57e12682015-09-16 11:30:19 -07003072 // If in the future the implementation is changed to lower undef values to
3073 // uninitialized registers, a FakeDef will be needed:
3074 // Context.insert(InstFakeDef::create(Func, Reg)); This is in order to
3075 // ensure that the live range of Reg is not overestimated. If the constant
3076 // being lowered is a 64 bit value, then the result should be split and the
3077 // lo and hi components will need to go in uninitialized registers.
Jan Voungfbdd2442015-07-15 12:36:20 -07003078 if (isVectorType(Ty))
3079 return makeVectorOfZeros(Ty, RegNum);
3080 return Ctx->getConstantZero(Ty);
3081 }
3082 return From;
3083}
3084
Jan Voungbefd03a2015-06-02 11:03:03 -07003085OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) {
3086 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand);
Andrew Scull57e12682015-09-16 11:30:19 -07003087 // It may be the case that address mode optimization already creates an
3088 // OperandARM32Mem, so in that case it wouldn't need another level of
3089 // transformation.
Jan Voungbefd03a2015-06-02 11:03:03 -07003090 if (Mem) {
3091 return llvm::cast<OperandARM32Mem>(legalize(Mem));
3092 }
Andrew Scull57e12682015-09-16 11:30:19 -07003093 // If we didn't do address mode optimization, then we only have a base/offset
3094 // to work with. ARM always requires a base register, so just use that to
3095 // hold the operand.
Andrew Scull97f460d2015-07-21 10:07:42 -07003096 Variable *Base = legalizeToReg(Operand);
Jan Voungbefd03a2015-06-02 11:03:03 -07003097 return OperandARM32Mem::create(
3098 Func, Ty, Base,
3099 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32)));
3100}
3101
Jan Voungb3401d22015-05-18 09:38:21 -07003102Variable *TargetARM32::makeReg(Type Type, int32_t RegNum) {
3103 // There aren't any 64-bit integer registers for ARM32.
3104 assert(Type != IceType_i64);
3105 Variable *Reg = Func->makeVariable(Type);
3106 if (RegNum == Variable::NoRegister)
Andrew Scull11c9a322015-08-28 14:24:14 -07003107 Reg->setMustHaveReg();
Jan Voungb3401d22015-05-18 09:38:21 -07003108 else
3109 Reg->setRegNum(RegNum);
3110 return Reg;
3111}
3112
Jan Voung55500db2015-05-26 14:25:40 -07003113void TargetARM32::alignRegisterPow2(Variable *Reg, uint32_t Align) {
3114 assert(llvm::isPowerOf2_32(Align));
Jan Voung0fa6c5a2015-06-01 11:04:04 -07003115 uint32_t RotateAmt;
Jan Voung55500db2015-05-26 14:25:40 -07003116 uint32_t Immed_8;
3117 Operand *Mask;
Andrew Scull57e12682015-09-16 11:30:19 -07003118 // Use AND or BIC to mask off the bits, depending on which immediate fits (if
3119 // it fits at all). Assume Align is usually small, in which case BIC works
3120 // better. Thus, this rounds down to the alignment.
Jan Voung55500db2015-05-26 14:25:40 -07003121 if (OperandARM32FlexImm::canHoldImm(Align - 1, &RotateAmt, &Immed_8)) {
3122 Mask = legalize(Ctx->getConstantInt32(Align - 1), Legal_Reg | Legal_Flex);
3123 _bic(Reg, Reg, Mask);
3124 } else {
3125 Mask = legalize(Ctx->getConstantInt32(-Align), Legal_Reg | Legal_Flex);
3126 _and(Reg, Reg, Mask);
3127 }
3128}
3129
Jan Voungb36ad9b2015-04-21 17:01:49 -07003130void TargetARM32::postLower() {
3131 if (Ctx->getFlags().getOptLevel() == Opt_m1)
3132 return;
Jan Voungb3401d22015-05-18 09:38:21 -07003133 inferTwoAddress();
Jan Voungb36ad9b2015-04-21 17:01:49 -07003134}
3135
3136void TargetARM32::makeRandomRegisterPermutation(
3137 llvm::SmallVectorImpl<int32_t> &Permutation,
Qining Luaee5fa82015-08-20 14:59:03 -07003138 const llvm::SmallBitVector &ExcludeRegisters, uint64_t Salt) const {
Jan Voungb36ad9b2015-04-21 17:01:49 -07003139 (void)Permutation;
3140 (void)ExcludeRegisters;
Qining Luaee5fa82015-08-20 14:59:03 -07003141 (void)Salt;
Jan Voungb2d50842015-05-12 09:53:50 -07003142 UnimplementedError(Func->getContext()->getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07003143}
3144
Jan Voung76bb0be2015-05-14 09:26:19 -07003145void TargetARM32::emit(const ConstantInteger32 *C) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -07003146 if (!BuildDefs::dump())
Jan Voung76bb0be2015-05-14 09:26:19 -07003147 return;
3148 Ostream &Str = Ctx->getStrEmit();
3149 Str << getConstantPrefix() << C->getValue();
Jan Voungb36ad9b2015-04-21 17:01:49 -07003150}
3151
Jan Voung76bb0be2015-05-14 09:26:19 -07003152void TargetARM32::emit(const ConstantInteger64 *) const {
3153 llvm::report_fatal_error("Not expecting to emit 64-bit integers");
Jan Voungb36ad9b2015-04-21 17:01:49 -07003154}
Jan Voung76bb0be2015-05-14 09:26:19 -07003155
3156void TargetARM32::emit(const ConstantFloat *C) const {
Jan Voungb3401d22015-05-18 09:38:21 -07003157 (void)C;
Jan Voung76bb0be2015-05-14 09:26:19 -07003158 UnimplementedError(Ctx->getFlags());
3159}
3160
3161void TargetARM32::emit(const ConstantDouble *C) const {
Jan Voungb3401d22015-05-18 09:38:21 -07003162 (void)C;
Jan Voung76bb0be2015-05-14 09:26:19 -07003163 UnimplementedError(Ctx->getFlags());
3164}
3165
3166void TargetARM32::emit(const ConstantUndef *) const {
3167 llvm::report_fatal_error("undef value encountered by emitter.");
3168}
Jan Voungb36ad9b2015-04-21 17:01:49 -07003169
3170TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
3171 : TargetDataLowering(Ctx) {}
3172
John Porto8b1a7052015-06-17 13:20:08 -07003173void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
3174 const IceString &SectionSuffix) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07003175 switch (Ctx->getFlags().getOutFileType()) {
3176 case FT_Elf: {
3177 ELFObjectWriter *Writer = Ctx->getObjectWriter();
John Porto8b1a7052015-06-17 13:20:08 -07003178 Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix);
Jan Voungb36ad9b2015-04-21 17:01:49 -07003179 } break;
3180 case FT_Asm:
3181 case FT_Iasm: {
3182 const IceString &TranslateOnly = Ctx->getFlags().getTranslateOnly();
3183 OstreamLocker L(Ctx);
John Porto8b1a7052015-06-17 13:20:08 -07003184 for (const VariableDeclaration *Var : Vars) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07003185 if (GlobalContext::matchSymbolName(Var->getName(), TranslateOnly)) {
John Porto8b1a7052015-06-17 13:20:08 -07003186 emitGlobal(*Var, SectionSuffix);
Jan Voungb36ad9b2015-04-21 17:01:49 -07003187 }
3188 }
3189 } break;
3190 }
3191}
3192
John Portoa83bfde2015-09-18 08:43:02 -07003193namespace {
3194template <typename T> struct ConstantPoolEmitterTraits;
3195
3196static_assert(sizeof(uint64_t) == 8,
3197 "uint64_t is supposed to be 8 bytes wide.");
3198
3199// TODO(jpp): implement the following when implementing constant randomization:
3200// * template <> struct ConstantPoolEmitterTraits<uint8_t>
3201// * template <> struct ConstantPoolEmitterTraits<uint16_t>
3202// * template <> struct ConstantPoolEmitterTraits<uint32_t>
3203template <> struct ConstantPoolEmitterTraits<float> {
3204 using ConstantType = ConstantFloat;
3205 static constexpr Type IceType = IceType_f32;
3206 // AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
3207 // about them being constexpr.
3208 static const char AsmTag[];
3209 static const char TypeName[];
3210 static uint64_t bitcastToUint64(float Value) {
3211 static_assert(sizeof(Value) == sizeof(uint32_t),
3212 "Float should be 4 bytes.");
3213 uint32_t IntValue = *reinterpret_cast<uint32_t *>(&Value);
3214 return static_cast<uint64_t>(IntValue);
3215 }
3216};
3217const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".long";
3218const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
3219
3220template <> struct ConstantPoolEmitterTraits<double> {
3221 using ConstantType = ConstantDouble;
3222 static constexpr Type IceType = IceType_f64;
3223 static const char AsmTag[];
3224 static const char TypeName[];
3225 static uint64_t bitcastToUint64(double Value) {
3226 static_assert(sizeof(double) == sizeof(uint64_t),
3227 "Double should be 8 bytes.");
3228 return *reinterpret_cast<uint64_t *>(&Value);
3229 }
3230};
3231const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
3232const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
3233
3234template <typename T>
3235void emitConstant(
3236 Ostream &Str,
3237 const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
3238 using Traits = ConstantPoolEmitterTraits<T>;
3239 Const->emitPoolLabel(Str);
3240 Str << ":\n\t" << Traits::AsmTag << "\t0x";
3241 T Value = Const->getValue();
3242 Str.write_hex(Traits::bitcastToUint64(Value));
3243 Str << "\t@" << Traits::TypeName << " " << Value << "\n";
3244}
3245
3246template <typename T> void emitConstantPool(GlobalContext *Ctx) {
3247 if (!BuildDefs::dump()) {
3248 return;
3249 }
3250
3251 using Traits = ConstantPoolEmitterTraits<T>;
3252 static constexpr size_t MinimumAlignment = 4;
3253 SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
3254 assert((Align % 4) == 0 && "Constants should be aligned");
3255 Ostream &Str = Ctx->getStrEmit();
3256 ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
3257
3258 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
3259 << "\n"
3260 << "\t.align\t" << Align << "\n";
3261
3262 if (Ctx->getFlags().shouldReorderPooledConstants()) {
3263 // TODO(jpp): add constant pooling.
3264 UnimplementedError(Ctx->getFlags());
3265 }
3266
3267 for (Constant *C : Pool) {
3268 if (!C->getShouldBePooled()) {
3269 continue;
3270 }
3271
3272 emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
3273 }
3274}
3275} // end of anonymous namespace
3276
John Porto0f86d032015-06-15 07:44:27 -07003277void TargetDataARM32::lowerConstants() {
Jan Voungb36ad9b2015-04-21 17:01:49 -07003278 if (Ctx->getFlags().getDisableTranslation())
3279 return;
John Portoa83bfde2015-09-18 08:43:02 -07003280 switch (Ctx->getFlags().getOutFileType()) {
3281 case FT_Elf:
3282 UnimplementedError(Ctx->getFlags());
3283 break;
3284 case FT_Asm: {
3285 OstreamLocker L(Ctx);
3286 emitConstantPool<float>(Ctx);
3287 emitConstantPool<double>(Ctx);
3288 break;
3289 }
3290 case FT_Iasm: {
3291 UnimplementedError(Ctx->getFlags());
3292 break;
3293 }
3294 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07003295}
3296
Andrew Scull86df4e92015-07-30 13:54:44 -07003297void TargetDataARM32::lowerJumpTables() {
3298 if (Ctx->getFlags().getDisableTranslation())
3299 return;
John Portoa83bfde2015-09-18 08:43:02 -07003300 switch (Ctx->getFlags().getOutFileType()) {
3301 case FT_Elf:
3302 UnimplementedError(Ctx->getFlags());
3303 break;
3304 case FT_Asm:
3305 // Already emitted from Cfg
3306 break;
3307 case FT_Iasm: {
3308 UnimplementedError(Ctx->getFlags());
3309 break;
3310 }
3311 }
Andrew Scull86df4e92015-07-30 13:54:44 -07003312}
3313
Jan Voungfb792842015-06-11 15:27:50 -07003314TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx)
Jan Voung6ec369e2015-06-30 11:03:15 -07003315 : TargetHeaderLowering(Ctx), CPUFeatures(Ctx->getFlags()) {}
Jan Voungfb792842015-06-11 15:27:50 -07003316
3317void TargetHeaderARM32::lower() {
3318 OstreamLocker L(Ctx);
3319 Ostream &Str = Ctx->getStrEmit();
3320 Str << ".syntax unified\n";
Andrew Scull57e12682015-09-16 11:30:19 -07003321 // Emit build attributes in format: .eabi_attribute TAG, VALUE. See Sec. 2 of
3322 // "Addenda to, and Errata in the ABI for the ARM architecture"
3323 // http://infocenter.arm.com
3324 // /help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf
Jan Voungfb792842015-06-11 15:27:50 -07003325 //
Andrew Scull57e12682015-09-16 11:30:19 -07003326 // Tag_conformance should be be emitted first in a file-scope sub-subsection
3327 // of the first public subsection of the attributes.
Jan Voungfb792842015-06-11 15:27:50 -07003328 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n";
Andrew Scull57e12682015-09-16 11:30:19 -07003329 // Chromebooks are at least A15, but do A9 for higher compat. For some
3330 // reason, the LLVM ARM asm parser has the .cpu directive override the mattr
3331 // specified on the commandline. So to test hwdiv, we need to set the .cpu
3332 // directive higher (can't just rely on --mattr=...).
Jan Voung6ec369e2015-06-30 11:03:15 -07003333 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) {
3334 Str << ".cpu cortex-a15\n";
3335 } else {
3336 Str << ".cpu cortex-a9\n";
3337 }
3338 Str << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n"
Jan Voungfb792842015-06-11 15:27:50 -07003339 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n";
3340 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n"
3341 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n";
Jan Voungfb792842015-06-11 15:27:50 -07003342 Str << ".fpu neon\n"
3343 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n"
3344 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n"
3345 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n"
3346 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n"
3347 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n"
3348 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n"
3349 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n"
3350 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n"
3351 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n"
3352 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n"
3353 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n"
3354 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n";
Jan Voung6ec369e2015-06-30 11:03:15 -07003355 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) {
3356 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n";
3357 }
Jan Voungfb792842015-06-11 15:27:50 -07003358 // Technically R9 is used for TLS with Sandboxing, and we reserve it.
3359 // However, for compatibility with current NaCl LLVM, don't claim that.
3360 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n";
3361}
3362
Jan Voungb36ad9b2015-04-21 17:01:49 -07003363} // end of namespace Ice