blob: d820bcabe78961b880548029dcf259dbc27611cb [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
Jim Stichnoth92a6e5b2015-12-02 16:52:44 -080011/// \brief Implements the TargetLoweringARM32 class, which consists almost
Andrew Scull9612d322015-07-06 14:53:25 -070012/// 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"
John Portoba6a67c2015-09-25 15:19:45 -070023#include "IceInstARM32.def"
Jan Voungb36ad9b2015-04-21 17:01:49 -070024#include "IceInstARM32.h"
John Porto4a5e6d02015-11-04 09:32:55 -080025#include "IceInstVarIter.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070026#include "IceLiveness.h"
27#include "IceOperand.h"
Jan Voung53483692015-07-16 10:47:46 -070028#include "IcePhiLoweringImpl.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070029#include "IceRegistersARM32.h"
30#include "IceTargetLoweringARM32.def"
Jan Voungb36ad9b2015-04-21 17:01:49 -070031#include "IceUtils.h"
John Porto67f8de92015-06-25 10:14:17 -070032#include "llvm/Support/MathExtras.h"
Jan Voungb36ad9b2015-04-21 17:01:49 -070033
John Portoa83bfde2015-09-18 08:43:02 -070034#include <algorithm>
John Porto98cc08c2015-11-24 12:30:01 -080035#include <array>
John Portoba6a67c2015-09-25 15:19:45 -070036#include <utility>
John Portoa83bfde2015-09-18 08:43:02 -070037
John Porto53611e22015-12-30 07:30:10 -080038namespace ARM32 {
39std::unique_ptr<::Ice::TargetLowering> createTargetLowering(::Ice::Cfg *Func) {
John Porto4a566862016-01-04 09:33:41 -080040 return ::Ice::ARM32::TargetARM32::create(Func);
John Porto53611e22015-12-30 07:30:10 -080041}
42
43std::unique_ptr<::Ice::TargetDataLowering>
44createTargetDataLowering(::Ice::GlobalContext *Ctx) {
John Porto4a566862016-01-04 09:33:41 -080045 return ::Ice::ARM32::TargetDataARM32::create(Ctx);
John Porto53611e22015-12-30 07:30:10 -080046}
47
48std::unique_ptr<::Ice::TargetHeaderLowering>
49createTargetHeaderLowering(::Ice::GlobalContext *Ctx) {
John Porto4a566862016-01-04 09:33:41 -080050 return ::Ice::ARM32::TargetHeaderARM32::create(Ctx);
John Porto53611e22015-12-30 07:30:10 -080051}
52
Karl Schimpf5403f5d2016-01-15 11:07:46 -080053void staticInit(::Ice::GlobalContext *Ctx) {
54 ::Ice::ARM32::TargetARM32::staticInit(Ctx);
Karl Schimpfd4699942016-04-02 09:55:31 -070055 if (Ice::getFlags().getUseNonsfi()) {
John Portodc619252016-02-10 15:57:16 -080056 // In nonsfi, we need to reference the _GLOBAL_OFFSET_TABLE_ for accessing
57 // globals. The GOT is an external symbol (i.e., it is not defined in the
58 // pexe) so we need to register it as such so that ELF emission won't barf
59 // on an "unknown" symbol. The GOT is added to the External symbols list
60 // here because staticInit() is invoked in a single-thread context.
Jim Stichnoth467ffe52016-03-29 15:01:06 -070061 Ctx->getConstantExternSym(Ctx->getGlobalString(::Ice::GlobalOffsetTable));
John Portodc619252016-02-10 15:57:16 -080062 }
Jim Stichnoth8ff4b282016-01-04 15:39:06 -080063}
Karl Schimpf57ec7df2016-01-15 08:11:00 -080064
Jim Stichnoth467ffe52016-03-29 15:01:06 -070065bool shouldBePooled(const ::Ice::Constant *C) {
66 return ::Ice::ARM32::TargetARM32::shouldBePooled(C);
67}
68
Nicolas Capens32f9cce2016-10-19 01:24:27 -040069::Ice::Type getPointerType() {
70 return ::Ice::ARM32::TargetARM32::getPointerType();
71}
72
John Porto53611e22015-12-30 07:30:10 -080073} // end of namespace ARM32
74
Jan Voungb36ad9b2015-04-21 17:01:49 -070075namespace Ice {
John Porto4a566862016-01-04 09:33:41 -080076namespace ARM32 {
Jan Voungb36ad9b2015-04-21 17:01:49 -070077
Karl Schimpf57ec7df2016-01-15 08:11:00 -080078namespace {
79
80/// SizeOf is used to obtain the size of an initializer list as a constexpr
81/// expression. This is only needed until our C++ library is updated to
82/// C++ 14 -- which defines constexpr members to std::initializer_list.
83class SizeOf {
84 SizeOf(const SizeOf &) = delete;
85 SizeOf &operator=(const SizeOf &) = delete;
86
87public:
88 constexpr SizeOf() : Size(0) {}
89 template <typename... T>
90 explicit constexpr SizeOf(T...)
91 : Size(__length<T...>::value) {}
92 constexpr SizeT size() const { return Size; }
93
94private:
95 template <typename T, typename... U> struct __length {
96 static constexpr std::size_t value = 1 + __length<U...>::value;
97 };
98
99 template <typename T> struct __length<T> {
100 static constexpr std::size_t value = 1;
101 };
102
103 const std::size_t Size;
104};
105
106} // end of anonymous namespace
107
John Porto149999e2016-01-04 13:45:26 -0800108// Defines the RegARM32::Table table with register information.
Karl Schimpf57ec7df2016-01-15 08:11:00 -0800109RegARM32::RegTableType RegARM32::RegTable[RegARM32::Reg_NUM] = {
110#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
111 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
112 { \
113 name, encode, cc_arg, scratch, preserved, stackptr, frameptr, isGPR, \
114 isInt, isI64Pair, isFP32, isFP64, isVec128, \
115 (SizeOf alias_init).size(), alias_init \
116 } \
117 ,
118 REGARM32_TABLE
119#undef X
120};
John Porto149999e2016-01-04 13:45:26 -0800121
Jan Voungb2d50842015-05-12 09:53:50 -0700122namespace {
Jan Voung3bfd99a2015-05-22 16:35:25 -0700123
Jan Voung3bfd99a2015-05-22 16:35:25 -0700124// The following table summarizes the logic for lowering the icmp instruction
Andrew Scull57e12682015-09-16 11:30:19 -0700125// for i32 and narrower types. Each icmp condition has a clear mapping to an
Jan Voung3bfd99a2015-05-22 16:35:25 -0700126// ARM32 conditional move instruction.
127
128const struct TableIcmp32_ {
129 CondARM32::Cond Mapping;
130} TableIcmp32[] = {
John Portoa4d100a2016-04-18 15:32:27 -0700131#define X(val, is_signed, swapped64, C_32, C1_64, C2_64, C_V, INV_V, NEG_V) \
Jan Voung3bfd99a2015-05-22 16:35:25 -0700132 { CondARM32::C_32 } \
133 ,
134 ICMPARM32_TABLE
135#undef X
136};
Jan Voung3bfd99a2015-05-22 16:35:25 -0700137
138// The following table summarizes the logic for lowering the icmp instruction
139// for the i64 type. Two conditional moves are needed for setting to 1 or 0.
Andrew Scull57e12682015-09-16 11:30:19 -0700140// The operands may need to be swapped, and there is a slight difference for
141// signed vs unsigned (comparing hi vs lo first, and using cmp vs sbc).
Jan Voung3bfd99a2015-05-22 16:35:25 -0700142const struct TableIcmp64_ {
143 bool IsSigned;
144 bool Swapped;
145 CondARM32::Cond C1, C2;
146} TableIcmp64[] = {
John Portoa4d100a2016-04-18 15:32:27 -0700147#define X(val, is_signed, swapped64, C_32, C1_64, C2_64, C_V, INV_V, NEG_V) \
Jan Voung3bfd99a2015-05-22 16:35:25 -0700148 { is_signed, swapped64, CondARM32::C1_64, CondARM32::C2_64 } \
149 ,
150 ICMPARM32_TABLE
151#undef X
152};
Jan Voung3bfd99a2015-05-22 16:35:25 -0700153
154CondARM32::Cond getIcmp32Mapping(InstIcmp::ICond Cond) {
Jim Stichnoth2d6c8262016-02-07 09:50:27 -0800155 assert(Cond < llvm::array_lengthof(TableIcmp32));
156 return TableIcmp32[Cond].Mapping;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700157}
158
Andrew Scull57e12682015-09-16 11:30:19 -0700159// In some cases, there are x-macros tables for both high-level and low-level
160// instructions/operands that use the same enum key value. The tables are kept
161// separate to maintain a proper separation between abstraction layers. There
162// is a risk that the tables could get out of sync if enum values are reordered
John Porto2f5534f2015-09-18 15:59:47 -0700163// or if entries are added or deleted. The following anonymous namespaces use
Jan Voung3bfd99a2015-05-22 16:35:25 -0700164// static_asserts to ensure everything is kept in sync.
165
166// Validate the enum values in ICMPARM32_TABLE.
John Porto2f5534f2015-09-18 15:59:47 -0700167namespace {
Andrew Scull57e12682015-09-16 11:30:19 -0700168// Define a temporary set of enum values based on low-level table entries.
John Porto2f5534f2015-09-18 15:59:47 -0700169enum _icmp_ll_enum {
John Portoa4d100a2016-04-18 15:32:27 -0700170#define X(val, is_signed, swapped64, C_32, C1_64, C2_64, C_V, INV_V, NEG_V) \
171 _icmp_ll_##val,
Jan Voung3bfd99a2015-05-22 16:35:25 -0700172 ICMPARM32_TABLE
173#undef X
174 _num
175};
176// Define a set of constants based on high-level table entries.
Manasij Mukherjee0c704172016-07-21 12:40:24 -0700177#define X(tag, reverse, str) \
178 static constexpr int _icmp_hl_##tag = InstIcmp::tag;
Jan Voung3bfd99a2015-05-22 16:35:25 -0700179ICEINSTICMP_TABLE
180#undef X
Andrew Scull57e12682015-09-16 11:30:19 -0700181// Define a set of constants based on low-level table entries, and ensure the
182// table entry keys are consistent.
John Portoa4d100a2016-04-18 15:32:27 -0700183#define X(val, is_signed, swapped64, C_32, C1_64, C2_64, C_V, INV_V, NEG_V) \
Jan Voung3bfd99a2015-05-22 16:35:25 -0700184 static_assert( \
John Porto2f5534f2015-09-18 15:59:47 -0700185 _icmp_ll_##val == _icmp_hl_##val, \
186 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #val);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700187ICMPARM32_TABLE
188#undef X
Andrew Scull57e12682015-09-16 11:30:19 -0700189// Repeat the static asserts with respect to the high-level table entries in
190// case the high-level table has extra entries.
Manasij Mukherjee0c704172016-07-21 12:40:24 -0700191#define X(tag, reverse, str) \
Jan Voung3bfd99a2015-05-22 16:35:25 -0700192 static_assert( \
John Porto2f5534f2015-09-18 15:59:47 -0700193 _icmp_hl_##tag == _icmp_ll_##tag, \
194 "Inconsistency between ICMPARM32_TABLE and ICEINSTICMP_TABLE: " #tag);
Jan Voung3bfd99a2015-05-22 16:35:25 -0700195ICEINSTICMP_TABLE
196#undef X
John Porto2f5534f2015-09-18 15:59:47 -0700197} // end of anonymous namespace
Jan Voung3bfd99a2015-05-22 16:35:25 -0700198
Jan Voung55500db2015-05-26 14:25:40 -0700199// Stack alignment
200const uint32_t ARM32_STACK_ALIGNMENT_BYTES = 16;
201
Andrew Scull57e12682015-09-16 11:30:19 -0700202// Value is in bytes. Return Value adjusted to the next highest multiple of the
203// stack alignment.
Jan Voung0fa6c5a2015-06-01 11:04:04 -0700204uint32_t applyStackAlignment(uint32_t Value) {
205 return Utils::applyAlignment(Value, ARM32_STACK_ALIGNMENT_BYTES);
206}
207
Andrew Scull57e12682015-09-16 11:30:19 -0700208// Value is in bytes. Return Value adjusted to the next highest multiple of the
209// stack alignment required for the given type.
Jan Voungb0a8c242015-06-18 15:00:14 -0700210uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) {
Andrew Scull57e12682015-09-16 11:30:19 -0700211 // Use natural alignment, except that normally (non-NaCl) ARM only aligns
212 // vectors to 8 bytes.
Jan Voungb0a8c242015-06-18 15:00:14 -0700213 // TODO(jvoung): Check this ...
214 size_t typeAlignInBytes = typeWidthInBytes(Ty);
215 if (isVectorType(Ty))
216 typeAlignInBytes = 8;
217 return Utils::applyAlignment(Value, typeAlignInBytes);
218}
219
Jan Voung6ec369e2015-06-30 11:03:15 -0700220// Conservatively check if at compile time we know that the operand is
221// definitely a non-zero integer.
222bool isGuaranteedNonzeroInt(const Operand *Op) {
223 if (auto *Const = llvm::dyn_cast_or_null<ConstantInteger32>(Op)) {
224 return Const->getValue() != 0;
225 }
226 return false;
227}
228
Jan Voungb2d50842015-05-12 09:53:50 -0700229} // end of anonymous namespace
230
Jan Voung6ec369e2015-06-30 11:03:15 -0700231TargetARM32Features::TargetARM32Features(const ClFlags &Flags) {
Jan Voungd062f732015-06-15 17:17:31 -0700232 static_assert(
233 (ARM32InstructionSet::End - ARM32InstructionSet::Begin) ==
234 (TargetInstructionSet::ARM32InstructionSet_End -
235 TargetInstructionSet::ARM32InstructionSet_Begin),
236 "ARM32InstructionSet range different from TargetInstructionSet");
Jan Voung6ec369e2015-06-30 11:03:15 -0700237 if (Flags.getTargetInstructionSet() !=
Jan Voungd062f732015-06-15 17:17:31 -0700238 TargetInstructionSet::BaseInstructionSet) {
239 InstructionSet = static_cast<ARM32InstructionSet>(
Jan Voung6ec369e2015-06-30 11:03:15 -0700240 (Flags.getTargetInstructionSet() -
Jan Voungd062f732015-06-15 17:17:31 -0700241 TargetInstructionSet::ARM32InstructionSet_Begin) +
242 ARM32InstructionSet::Begin);
243 }
Jan Voung6ec369e2015-06-30 11:03:15 -0700244}
245
John Porto2187c842015-12-16 07:48:25 -0800246namespace {
247constexpr SizeT NumGPRArgs =
248#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -0800249 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Porto2187c842015-12-16 07:48:25 -0800250 +(((cc_arg) > 0) ? 1 : 0)
251 REGARM32_GPR_TABLE
252#undef X
253 ;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800254std::array<RegNumT, NumGPRArgs> GPRArgInitializer;
John Porto2187c842015-12-16 07:48:25 -0800255
256constexpr SizeT NumI64Args =
257#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -0800258 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Porto2187c842015-12-16 07:48:25 -0800259 +(((cc_arg) > 0) ? 1 : 0)
260 REGARM32_I64PAIR_TABLE
261#undef X
262 ;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800263std::array<RegNumT, NumI64Args> I64ArgInitializer;
John Porto2187c842015-12-16 07:48:25 -0800264
265constexpr SizeT NumFP32Args =
266#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -0800267 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Porto2187c842015-12-16 07:48:25 -0800268 +(((cc_arg) > 0) ? 1 : 0)
269 REGARM32_FP32_TABLE
270#undef X
271 ;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800272std::array<RegNumT, NumFP32Args> FP32ArgInitializer;
John Porto2187c842015-12-16 07:48:25 -0800273
274constexpr SizeT NumFP64Args =
275#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -0800276 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Porto2187c842015-12-16 07:48:25 -0800277 +(((cc_arg) > 0) ? 1 : 0)
278 REGARM32_FP64_TABLE
279#undef X
280 ;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800281std::array<RegNumT, NumFP64Args> FP64ArgInitializer;
John Porto2187c842015-12-16 07:48:25 -0800282
283constexpr SizeT NumVec128Args =
284#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -0800285 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Porto2187c842015-12-16 07:48:25 -0800286 +(((cc_arg > 0)) ? 1 : 0)
287 REGARM32_VEC128_TABLE
288#undef X
289 ;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800290std::array<RegNumT, NumVec128Args> Vec128ArgInitializer;
Jim Stichnoth2544d4d2016-01-22 13:07:46 -0800291
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700292const char *getRegClassName(RegClass C) {
Jim Stichnoth2544d4d2016-01-22 13:07:46 -0800293 auto ClassNum = static_cast<RegARM32::RegClassARM32>(C);
294 assert(ClassNum < RegARM32::RCARM32_NUM);
295 switch (ClassNum) {
296 default:
297 assert(C < RC_Target);
298 return regClassString(C);
Karl Schimpfe54e5302016-02-10 13:38:10 -0800299 // Add handling of new register classes below.
300 case RegARM32::RCARM32_QtoS:
301 return "QtoS";
Jim Stichnoth2544d4d2016-01-22 13:07:46 -0800302 }
303}
304
John Porto2187c842015-12-16 07:48:25 -0800305} // end of anonymous namespace
306
Jan Voung6ec369e2015-06-30 11:03:15 -0700307TargetARM32::TargetARM32(Cfg *Func)
John Portoac2388c2016-01-22 07:10:56 -0800308 : TargetLowering(Func), NeedSandboxing(SandboxingType == ST_NaCl),
Karl Schimpfd4699942016-04-02 09:55:31 -0700309 CPUFeatures(getFlags()) {}
Jim Stichnoth94844f12015-11-04 16:06:16 -0800310
Karl Schimpf5403f5d2016-01-15 11:07:46 -0800311void TargetARM32::staticInit(GlobalContext *Ctx) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800312 RegNumT::setLimit(RegARM32::Reg_NUM);
Jan Voung86ebec12015-08-09 07:58:35 -0700313 // Limit this size (or do all bitsets need to be the same width)???
John Portoe82b5602016-02-24 15:58:55 -0800314 SmallBitVector IntegerRegisters(RegARM32::Reg_NUM);
315 SmallBitVector I64PairRegisters(RegARM32::Reg_NUM);
316 SmallBitVector Float32Registers(RegARM32::Reg_NUM);
317 SmallBitVector Float64Registers(RegARM32::Reg_NUM);
318 SmallBitVector VectorRegisters(RegARM32::Reg_NUM);
319 SmallBitVector QtoSRegisters(RegARM32::Reg_NUM);
320 SmallBitVector InvalidRegisters(RegARM32::Reg_NUM);
Eric Holk658bae22016-02-08 15:22:18 -0800321 const unsigned EncodedReg_q8 = RegARM32::RegTable[RegARM32::Reg_q8].Encoding;
John Porto149999e2016-01-04 13:45:26 -0800322 for (int i = 0; i < RegARM32::Reg_NUM; ++i) {
Karl Schimpf57ec7df2016-01-15 08:11:00 -0800323 const auto &Entry = RegARM32::RegTable[i];
John Porto149999e2016-01-04 13:45:26 -0800324 IntegerRegisters[i] = Entry.IsInt;
325 I64PairRegisters[i] = Entry.IsI64Pair;
326 Float32Registers[i] = Entry.IsFP32;
327 Float64Registers[i] = Entry.IsFP64;
328 VectorRegisters[i] = Entry.IsVec128;
John Porto149999e2016-01-04 13:45:26 -0800329 RegisterAliases[i].resize(RegARM32::Reg_NUM);
Eric Holk658bae22016-02-08 15:22:18 -0800330 // TODO(eholk): It would be better to store a QtoS flag in the
331 // IceRegistersARM32 table than to compare their encodings here.
332 QtoSRegisters[i] = Entry.IsVec128 && Entry.Encoding < EncodedReg_q8;
John Porto149999e2016-01-04 13:45:26 -0800333 for (int j = 0; j < Entry.NumAliases; ++j) {
334 assert(i == j || !RegisterAliases[i][Entry.Aliases[j]]);
335 RegisterAliases[i].set(Entry.Aliases[j]);
336 }
337 assert(RegisterAliases[i][i]);
338 if (Entry.CCArg <= 0) {
339 continue;
340 }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800341 const auto RegNum = RegNumT::fromInt(i);
John Porto149999e2016-01-04 13:45:26 -0800342 if (Entry.IsGPR) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800343 GPRArgInitializer[Entry.CCArg - 1] = RegNum;
John Porto149999e2016-01-04 13:45:26 -0800344 } else if (Entry.IsI64Pair) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800345 I64ArgInitializer[Entry.CCArg - 1] = RegNum;
John Porto149999e2016-01-04 13:45:26 -0800346 } else if (Entry.IsFP32) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800347 FP32ArgInitializer[Entry.CCArg - 1] = RegNum;
John Porto149999e2016-01-04 13:45:26 -0800348 } else if (Entry.IsFP64) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800349 FP64ArgInitializer[Entry.CCArg - 1] = RegNum;
John Porto149999e2016-01-04 13:45:26 -0800350 } else if (Entry.IsVec128) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800351 Vec128ArgInitializer[Entry.CCArg - 1] = RegNum;
John Porto149999e2016-01-04 13:45:26 -0800352 }
John Porto2187c842015-12-16 07:48:25 -0800353 }
Jan Voungb36ad9b2015-04-21 17:01:49 -0700354 TypeToRegisterSet[IceType_void] = InvalidRegisters;
355 TypeToRegisterSet[IceType_i1] = IntegerRegisters;
356 TypeToRegisterSet[IceType_i8] = IntegerRegisters;
357 TypeToRegisterSet[IceType_i16] = IntegerRegisters;
358 TypeToRegisterSet[IceType_i32] = IntegerRegisters;
John Portoed2c06b2015-10-01 15:27:15 -0700359 TypeToRegisterSet[IceType_i64] = I64PairRegisters;
Jan Voung86ebec12015-08-09 07:58:35 -0700360 TypeToRegisterSet[IceType_f32] = Float32Registers;
361 TypeToRegisterSet[IceType_f64] = Float64Registers;
Jan Voungb36ad9b2015-04-21 17:01:49 -0700362 TypeToRegisterSet[IceType_v4i1] = VectorRegisters;
363 TypeToRegisterSet[IceType_v8i1] = VectorRegisters;
364 TypeToRegisterSet[IceType_v16i1] = VectorRegisters;
365 TypeToRegisterSet[IceType_v16i8] = VectorRegisters;
366 TypeToRegisterSet[IceType_v8i16] = VectorRegisters;
367 TypeToRegisterSet[IceType_v4i32] = VectorRegisters;
368 TypeToRegisterSet[IceType_v4f32] = VectorRegisters;
Eric Holk658bae22016-02-08 15:22:18 -0800369 TypeToRegisterSet[RegARM32::RCARM32_QtoS] = QtoSRegisters;
Karl Schimpf5403f5d2016-01-15 11:07:46 -0800370
Jim Stichnothb40595a2016-01-29 06:14:31 -0800371 for (size_t i = 0; i < llvm::array_lengthof(TypeToRegisterSet); ++i)
372 TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i];
373
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700374 filterTypeToRegisterSet(Ctx, RegARM32::Reg_NUM, TypeToRegisterSet,
375 llvm::array_lengthof(TypeToRegisterSet),
376 [](RegNumT RegNum) -> std::string {
377 // This function simply removes ", " from the
378 // register name.
379 std::string Name = RegARM32::getRegName(RegNum);
380 constexpr const char RegSeparator[] = ", ";
381 constexpr size_t RegSeparatorWidth =
382 llvm::array_lengthof(RegSeparator) - 1;
383 for (size_t Pos = Name.find(RegSeparator);
384 Pos != std::string::npos;
385 Pos = Name.find(RegSeparator)) {
386 Name.replace(Pos, RegSeparatorWidth, "");
387 }
388 return Name;
389 },
390 getRegClassName);
Jan Voungb36ad9b2015-04-21 17:01:49 -0700391}
392
John Porto578f1162015-10-06 06:54:42 -0700393namespace {
394void copyRegAllocFromInfWeightVariable64On32(const VarList &Vars) {
395 for (Variable *Var : Vars) {
396 auto *Var64 = llvm::dyn_cast<Variable64On32>(Var);
397 if (!Var64) {
398 // This is not the variable we are looking for.
399 continue;
400 }
John Porto4b6e4b42016-02-17 05:00:59 -0800401 // only allow infinite-weight i64 temporaries to be register allocated.
402 assert(!Var64->hasReg() || Var64->mustHaveReg());
John Porto578f1162015-10-06 06:54:42 -0700403 if (!Var64->hasReg()) {
404 continue;
405 }
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800406 const auto FirstReg =
407 RegNumT::fixme(RegARM32::getI64PairFirstGPRNum(Var->getRegNum()));
John Porto578f1162015-10-06 06:54:42 -0700408 // This assumes little endian.
409 Variable *Lo = Var64->getLo();
410 Variable *Hi = Var64->getHi();
411 assert(Lo->hasReg() == Hi->hasReg());
412 if (Lo->hasReg()) {
413 continue;
414 }
415 Lo->setRegNum(FirstReg);
416 Lo->setMustHaveReg();
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800417 Hi->setRegNum(RegNumT::fixme(FirstReg + 1));
John Porto578f1162015-10-06 06:54:42 -0700418 Hi->setMustHaveReg();
419 }
420}
421} // end of anonymous namespace
422
John Portof4198542015-11-20 14:17:23 -0800423uint32_t TargetARM32::getCallStackArgumentsSizeBytes(const InstCall *Call) {
424 TargetARM32::CallingConv CC;
Jim Stichnoth8aa39662016-02-10 11:20:30 -0800425 RegNumT DummyReg;
John Portof4198542015-11-20 14:17:23 -0800426 size_t OutArgsSizeBytes = 0;
427 for (SizeT i = 0, NumArgs = Call->getNumArgs(); i < NumArgs; ++i) {
428 Operand *Arg = legalizeUndef(Call->getArg(i));
John Porto2187c842015-12-16 07:48:25 -0800429 const Type Ty = Arg->getType();
430 if (isScalarIntegerType(Ty)) {
431 if (CC.argInGPR(Ty, &DummyReg)) {
John Portof4198542015-11-20 14:17:23 -0800432 continue;
433 }
434 } else {
John Porto2187c842015-12-16 07:48:25 -0800435 if (CC.argInVFP(Ty, &DummyReg)) {
John Portof4198542015-11-20 14:17:23 -0800436 continue;
437 }
438 }
439
440 OutArgsSizeBytes = applyStackAlignmentTy(OutArgsSizeBytes, Ty);
441 OutArgsSizeBytes += typeWidthInBytesOnStack(Ty);
442 }
443
444 return applyStackAlignment(OutArgsSizeBytes);
445}
446
John Portoc39ec102015-12-01 13:00:43 -0800447void TargetARM32::genTargetHelperCallFor(Inst *Instr) {
448 constexpr bool NoTailCall = false;
449 constexpr bool IsTargetHelperCall = true;
450
451 switch (Instr->getKind()) {
452 default:
453 return;
454 case Inst::Arithmetic: {
455 Variable *Dest = Instr->getDest();
456 const Type DestTy = Dest->getType();
457 const InstArithmetic::OpKind Op =
458 llvm::cast<InstArithmetic>(Instr)->getOp();
Eric Holkcfc25532016-02-09 17:47:58 -0800459 if (isVectorType(DestTy)) {
460 switch (Op) {
461 default:
462 break;
463 case InstArithmetic::Fdiv:
Eric Holk916e37b2016-02-17 13:03:29 -0800464 case InstArithmetic::Frem:
Eric Holkcfc25532016-02-09 17:47:58 -0800465 case InstArithmetic::Sdiv:
Eric Holk916e37b2016-02-17 13:03:29 -0800466 case InstArithmetic::Srem:
467 case InstArithmetic::Udiv:
468 case InstArithmetic::Urem:
Eric Holkcfc25532016-02-09 17:47:58 -0800469 scalarizeArithmetic(Op, Dest, Instr->getSrc(0), Instr->getSrc(1));
470 Instr->setDeleted();
471 return;
472 }
473 }
John Portoc39ec102015-12-01 13:00:43 -0800474 switch (DestTy) {
475 default:
476 return;
477 case IceType_i64: {
478 // Technically, ARM has its own aeabi routines, but we can use the
479 // non-aeabi routine as well. LLVM uses __aeabi_ldivmod for div, but uses
480 // the more standard __moddi3 for rem.
Karl Schimpf20070e82016-03-17 13:30:13 -0700481 RuntimeHelper HelperID = RuntimeHelper::H_Num;
John Portoc39ec102015-12-01 13:00:43 -0800482 switch (Op) {
483 default:
484 return;
485 case InstArithmetic::Udiv:
Karl Schimpf20070e82016-03-17 13:30:13 -0700486 HelperID = RuntimeHelper::H_udiv_i64;
John Portoc39ec102015-12-01 13:00:43 -0800487 break;
488 case InstArithmetic::Sdiv:
Karl Schimpf20070e82016-03-17 13:30:13 -0700489 HelperID = RuntimeHelper::H_sdiv_i64;
John Portoc39ec102015-12-01 13:00:43 -0800490 break;
491 case InstArithmetic::Urem:
Karl Schimpf20070e82016-03-17 13:30:13 -0700492 HelperID = RuntimeHelper::H_urem_i64;
John Portoc39ec102015-12-01 13:00:43 -0800493 break;
494 case InstArithmetic::Srem:
Karl Schimpf20070e82016-03-17 13:30:13 -0700495 HelperID = RuntimeHelper::H_srem_i64;
John Portoc39ec102015-12-01 13:00:43 -0800496 break;
497 }
Karl Schimpf20070e82016-03-17 13:30:13 -0700498 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(HelperID);
John Portoc39ec102015-12-01 13:00:43 -0800499 ARM32HelpersPreamble[TargetHelper] = &TargetARM32::preambleDivRem;
500 constexpr SizeT MaxArgs = 2;
John Porto1d937a82015-12-17 06:19:34 -0800501 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
502 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800503 Call->addArg(Instr->getSrc(0));
504 Call->addArg(Instr->getSrc(1));
John Portoc39ec102015-12-01 13:00:43 -0800505 Instr->setDeleted();
506 return;
507 }
508 case IceType_i32:
509 case IceType_i16:
510 case IceType_i8: {
511 const bool HasHWDiv = hasCPUFeature(TargetARM32Features::HWDivArm);
512 InstCast::OpKind CastKind;
Karl Schimpf20070e82016-03-17 13:30:13 -0700513 RuntimeHelper HelperID = RuntimeHelper::H_Num;
John Portoc39ec102015-12-01 13:00:43 -0800514 switch (Op) {
515 default:
516 return;
517 case InstArithmetic::Udiv:
Karl Schimpf20070e82016-03-17 13:30:13 -0700518 HelperID = HasHWDiv ? RuntimeHelper::H_Num : RuntimeHelper::H_udiv_i32;
John Portoc39ec102015-12-01 13:00:43 -0800519 CastKind = InstCast::Zext;
520 break;
521 case InstArithmetic::Sdiv:
Karl Schimpf20070e82016-03-17 13:30:13 -0700522 HelperID = HasHWDiv ? RuntimeHelper::H_Num : RuntimeHelper::H_sdiv_i32;
John Portoc39ec102015-12-01 13:00:43 -0800523 CastKind = InstCast::Sext;
524 break;
525 case InstArithmetic::Urem:
Karl Schimpf20070e82016-03-17 13:30:13 -0700526 HelperID = HasHWDiv ? RuntimeHelper::H_Num : RuntimeHelper::H_urem_i32;
John Portoc39ec102015-12-01 13:00:43 -0800527 CastKind = InstCast::Zext;
528 break;
529 case InstArithmetic::Srem:
Karl Schimpf20070e82016-03-17 13:30:13 -0700530 HelperID = HasHWDiv ? RuntimeHelper::H_Num : RuntimeHelper::H_srem_i32;
John Portoc39ec102015-12-01 13:00:43 -0800531 CastKind = InstCast::Sext;
532 break;
533 }
Karl Schimpf20070e82016-03-17 13:30:13 -0700534 if (HelperID == RuntimeHelper::H_Num) {
535 // HelperID should only ever be undefined when the processor does not
John Portoc39ec102015-12-01 13:00:43 -0800536 // have a hardware divider. If any other helpers are ever introduced,
537 // the following assert will have to be modified.
538 assert(HasHWDiv);
539 return;
540 }
541 Operand *Src0 = Instr->getSrc(0);
542 Operand *Src1 = Instr->getSrc(1);
543 if (DestTy != IceType_i32) {
544 // Src0 and Src1 have to be zero-, or signed-extended to i32. For Src0,
545 // we just insert a InstCast right before the call to the helper.
546 Variable *Src0_32 = Func->makeVariable(IceType_i32);
John Porto1d937a82015-12-17 06:19:34 -0800547 Context.insert<InstCast>(CastKind, Src0_32, Src0);
John Portoc39ec102015-12-01 13:00:43 -0800548 Src0 = Src0_32;
549
550 // For extending Src1, we will just insert an InstCast if Src1 is not a
551 // Constant. If it is, then we extend it here, and not during program
552 // runtime. This allows preambleDivRem to optimize-out the div-by-0
553 // check.
554 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
555 const int32_t ShAmt = (DestTy == IceType_i16) ? 16 : 24;
556 int32_t NewC = C->getValue();
557 if (CastKind == InstCast::Zext) {
558 NewC &= ~(0x80000000l >> ShAmt);
559 } else {
560 NewC = (NewC << ShAmt) >> ShAmt;
561 }
562 Src1 = Ctx->getConstantInt32(NewC);
563 } else {
564 Variable *Src1_32 = Func->makeVariable(IceType_i32);
John Porto1d937a82015-12-17 06:19:34 -0800565 Context.insert<InstCast>(CastKind, Src1_32, Src1);
John Portoc39ec102015-12-01 13:00:43 -0800566 Src1 = Src1_32;
567 }
568 }
Karl Schimpf20070e82016-03-17 13:30:13 -0700569 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(HelperID);
John Portoc39ec102015-12-01 13:00:43 -0800570 ARM32HelpersPreamble[TargetHelper] = &TargetARM32::preambleDivRem;
571 constexpr SizeT MaxArgs = 2;
John Porto1d937a82015-12-17 06:19:34 -0800572 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
573 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800574 assert(Src0->getType() == IceType_i32);
575 Call->addArg(Src0);
576 assert(Src1->getType() == IceType_i32);
577 Call->addArg(Src1);
John Portoc39ec102015-12-01 13:00:43 -0800578 Instr->setDeleted();
579 return;
580 }
581 case IceType_f64:
582 case IceType_f32: {
583 if (Op != InstArithmetic::Frem) {
584 return;
585 }
586 constexpr SizeT MaxArgs = 2;
Karl Schimpf20070e82016-03-17 13:30:13 -0700587 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(
588 DestTy == IceType_f32 ? RuntimeHelper::H_frem_f32
589 : RuntimeHelper::H_frem_f64);
John Porto1d937a82015-12-17 06:19:34 -0800590 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
591 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800592 Call->addArg(Instr->getSrc(0));
593 Call->addArg(Instr->getSrc(1));
John Portoc39ec102015-12-01 13:00:43 -0800594 Instr->setDeleted();
595 return;
596 }
597 }
598 llvm::report_fatal_error("Control flow should never have reached here.");
599 }
600 case Inst::Cast: {
601 Variable *Dest = Instr->getDest();
602 Operand *Src0 = Instr->getSrc(0);
603 const Type DestTy = Dest->getType();
John Porto7e6aa5a2016-03-02 15:10:19 -0800604 const Type SrcTy = Src0->getType();
Eric Holkcc69fa22016-02-10 13:07:06 -0800605 auto *CastInstr = llvm::cast<InstCast>(Instr);
606 const InstCast::OpKind CastKind = CastInstr->getCastKind();
607
John Portoc39ec102015-12-01 13:00:43 -0800608 switch (CastKind) {
609 default:
610 return;
611 case InstCast::Fptosi:
612 case InstCast::Fptoui: {
613 if (DestTy != IceType_i64) {
614 return;
615 }
616 const bool DestIsSigned = CastKind == InstCast::Fptosi;
John Porto7e6aa5a2016-03-02 15:10:19 -0800617 const bool Src0IsF32 = isFloat32Asserting32Or64(SrcTy);
Karl Schimpf20070e82016-03-17 13:30:13 -0700618 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(
619 Src0IsF32 ? (DestIsSigned ? RuntimeHelper::H_fptosi_f32_i64
620 : RuntimeHelper::H_fptoui_f32_i64)
621 : (DestIsSigned ? RuntimeHelper::H_fptosi_f64_i64
622 : RuntimeHelper::H_fptoui_f64_i64));
John Portoc39ec102015-12-01 13:00:43 -0800623 static constexpr SizeT MaxArgs = 1;
John Porto1d937a82015-12-17 06:19:34 -0800624 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
625 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800626 Call->addArg(Src0);
John Portoc39ec102015-12-01 13:00:43 -0800627 Instr->setDeleted();
628 return;
629 }
630 case InstCast::Sitofp:
631 case InstCast::Uitofp: {
John Porto7e6aa5a2016-03-02 15:10:19 -0800632 if (SrcTy != IceType_i64) {
John Portoc39ec102015-12-01 13:00:43 -0800633 return;
634 }
635 const bool SourceIsSigned = CastKind == InstCast::Sitofp;
636 const bool DestIsF32 = isFloat32Asserting32Or64(Dest->getType());
Karl Schimpf20070e82016-03-17 13:30:13 -0700637 Operand *TargetHelper = Ctx->getRuntimeHelperFunc(
638 DestIsF32 ? (SourceIsSigned ? RuntimeHelper::H_sitofp_i64_f32
639 : RuntimeHelper::H_uitofp_i64_f32)
640 : (SourceIsSigned ? RuntimeHelper::H_sitofp_i64_f64
641 : RuntimeHelper::H_uitofp_i64_f64));
John Portoc39ec102015-12-01 13:00:43 -0800642 static constexpr SizeT MaxArgs = 1;
John Porto1d937a82015-12-17 06:19:34 -0800643 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
644 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800645 Call->addArg(Src0);
John Portoc39ec102015-12-01 13:00:43 -0800646 Instr->setDeleted();
647 return;
648 }
John Porto7e6aa5a2016-03-02 15:10:19 -0800649 case InstCast::Bitcast: {
650 if (DestTy == SrcTy) {
651 return;
652 }
653 Variable *CallDest = Dest;
Karl Schimpf20070e82016-03-17 13:30:13 -0700654 RuntimeHelper HelperID = RuntimeHelper::H_Num;
John Porto7e6aa5a2016-03-02 15:10:19 -0800655 switch (DestTy) {
656 default:
657 return;
658 case IceType_i8:
659 assert(SrcTy == IceType_v8i1);
Karl Schimpf20070e82016-03-17 13:30:13 -0700660 HelperID = RuntimeHelper::H_bitcast_8xi1_i8;
John Porto7e6aa5a2016-03-02 15:10:19 -0800661 CallDest = Func->makeVariable(IceType_i32);
662 break;
663 case IceType_i16:
664 assert(SrcTy == IceType_v16i1);
Karl Schimpf20070e82016-03-17 13:30:13 -0700665 HelperID = RuntimeHelper::H_bitcast_16xi1_i16;
John Porto7e6aa5a2016-03-02 15:10:19 -0800666 CallDest = Func->makeVariable(IceType_i32);
667 break;
668 case IceType_v8i1: {
669 assert(SrcTy == IceType_i8);
Karl Schimpf20070e82016-03-17 13:30:13 -0700670 HelperID = RuntimeHelper::H_bitcast_i8_8xi1;
John Porto7e6aa5a2016-03-02 15:10:19 -0800671 Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
672 // Arguments to functions are required to be at least 32 bits wide.
673 Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
674 Src0 = Src0AsI32;
675 } break;
676 case IceType_v16i1: {
677 assert(SrcTy == IceType_i16);
Karl Schimpf20070e82016-03-17 13:30:13 -0700678 HelperID = RuntimeHelper::H_bitcast_i16_16xi1;
John Porto7e6aa5a2016-03-02 15:10:19 -0800679 Variable *Src0AsI32 = Func->makeVariable(stackSlotType());
680 // Arguments to functions are required to be at least 32 bits wide.
681 Context.insert<InstCast>(InstCast::Zext, Src0AsI32, Src0);
682 Src0 = Src0AsI32;
683 } break;
684 }
John Porto7e6aa5a2016-03-02 15:10:19 -0800685 constexpr SizeT MaxSrcs = 1;
Karl Schimpf20070e82016-03-17 13:30:13 -0700686 InstCall *Call = makeHelperCall(HelperID, CallDest, MaxSrcs);
John Porto7e6aa5a2016-03-02 15:10:19 -0800687 Call->addArg(Src0);
688 Context.insert(Call);
689 // The PNaCl ABI disallows i8/i16 return types, so truncate the helper
690 // call result to the appropriate type as necessary.
691 if (CallDest->getType() != Dest->getType())
692 Context.insert<InstCast>(InstCast::Trunc, Dest, CallDest);
693 Instr->setDeleted();
694 return;
695 }
John Portoe88c7de2016-04-14 11:51:38 -0700696 case InstCast::Trunc: {
697 if (DestTy == SrcTy) {
698 return;
699 }
700 if (!isVectorType(SrcTy)) {
701 return;
702 }
703 assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
704 assert(typeElementType(DestTy) == IceType_i1);
705 assert(isVectorIntegerType(SrcTy));
706 return;
707 }
708 case InstCast::Sext:
709 case InstCast::Zext: {
710 if (DestTy == SrcTy) {
711 return;
712 }
713 if (!isVectorType(DestTy)) {
714 return;
715 }
716 assert(typeNumElements(DestTy) == typeNumElements(SrcTy));
717 assert(typeElementType(SrcTy) == IceType_i1);
718 assert(isVectorIntegerType(DestTy));
719 return;
720 }
John Portoc39ec102015-12-01 13:00:43 -0800721 }
722 llvm::report_fatal_error("Control flow should never have reached here.");
723 }
724 case Inst::IntrinsicCall: {
725 Variable *Dest = Instr->getDest();
726 auto *IntrinsicCall = llvm::cast<InstIntrinsicCall>(Instr);
727 Intrinsics::IntrinsicID ID = IntrinsicCall->getIntrinsicInfo().ID;
728 switch (ID) {
729 default:
730 return;
731 case Intrinsics::Ctpop: {
732 Operand *Src0 = IntrinsicCall->getArg(0);
Karl Schimpf20070e82016-03-17 13:30:13 -0700733 Operand *TargetHelper =
734 Ctx->getRuntimeHelperFunc(isInt32Asserting32Or64(Src0->getType())
735 ? RuntimeHelper::H_call_ctpop_i32
736 : RuntimeHelper::H_call_ctpop_i64);
John Portoc39ec102015-12-01 13:00:43 -0800737 static constexpr SizeT MaxArgs = 1;
John Porto1d937a82015-12-17 06:19:34 -0800738 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
739 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800740 Call->addArg(Src0);
John Portoc39ec102015-12-01 13:00:43 -0800741 Instr->setDeleted();
742 if (Src0->getType() == IceType_i64) {
743 ARM32HelpersPostamble[TargetHelper] = &TargetARM32::postambleCtpop64;
744 }
745 return;
746 }
747 case Intrinsics::Longjmp: {
748 static constexpr SizeT MaxArgs = 2;
749 static constexpr Variable *NoDest = nullptr;
Karl Schimpf20070e82016-03-17 13:30:13 -0700750 Operand *TargetHelper =
751 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_longjmp);
John Porto1d937a82015-12-17 06:19:34 -0800752 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
753 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800754 Call->addArg(IntrinsicCall->getArg(0));
755 Call->addArg(IntrinsicCall->getArg(1));
John Portoc39ec102015-12-01 13:00:43 -0800756 Instr->setDeleted();
757 return;
758 }
759 case Intrinsics::Memcpy: {
760 // In the future, we could potentially emit an inline memcpy/memset, etc.
761 // for intrinsic calls w/ a known length.
762 static constexpr SizeT MaxArgs = 3;
763 static constexpr Variable *NoDest = nullptr;
Karl Schimpf20070e82016-03-17 13:30:13 -0700764 Operand *TargetHelper =
765 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memcpy);
John Porto1d937a82015-12-17 06:19:34 -0800766 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
767 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800768 Call->addArg(IntrinsicCall->getArg(0));
769 Call->addArg(IntrinsicCall->getArg(1));
770 Call->addArg(IntrinsicCall->getArg(2));
John Portoc39ec102015-12-01 13:00:43 -0800771 Instr->setDeleted();
772 return;
773 }
774 case Intrinsics::Memmove: {
775 static constexpr SizeT MaxArgs = 3;
776 static constexpr Variable *NoDest = nullptr;
Karl Schimpf20070e82016-03-17 13:30:13 -0700777 Operand *TargetHelper =
778 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memmove);
John Porto1d937a82015-12-17 06:19:34 -0800779 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
780 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800781 Call->addArg(IntrinsicCall->getArg(0));
782 Call->addArg(IntrinsicCall->getArg(1));
783 Call->addArg(IntrinsicCall->getArg(2));
John Portoc39ec102015-12-01 13:00:43 -0800784 Instr->setDeleted();
785 return;
786 }
787 case Intrinsics::Memset: {
788 // The value operand needs to be extended to a stack slot size because the
789 // PNaCl ABI requires arguments to be at least 32 bits wide.
790 Operand *ValOp = IntrinsicCall->getArg(1);
791 assert(ValOp->getType() == IceType_i8);
792 Variable *ValExt = Func->makeVariable(stackSlotType());
John Porto1d937a82015-12-17 06:19:34 -0800793 Context.insert<InstCast>(InstCast::Zext, ValExt, ValOp);
John Portoc39ec102015-12-01 13:00:43 -0800794
795 // Technically, ARM has its own __aeabi_memset, but we can use plain
796 // memset too. The value and size argument need to be flipped if we ever
797 // decide to use __aeabi_memset.
798 static constexpr SizeT MaxArgs = 3;
799 static constexpr Variable *NoDest = nullptr;
Karl Schimpf20070e82016-03-17 13:30:13 -0700800 Operand *TargetHelper =
801 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_memset);
John Porto1d937a82015-12-17 06:19:34 -0800802 auto *Call = Context.insert<InstCall>(MaxArgs, NoDest, TargetHelper,
803 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800804 Call->addArg(IntrinsicCall->getArg(0));
805 Call->addArg(ValExt);
806 Call->addArg(IntrinsicCall->getArg(2));
John Portoc39ec102015-12-01 13:00:43 -0800807 Instr->setDeleted();
808 return;
809 }
810 case Intrinsics::NaClReadTP: {
John Portodc619252016-02-10 15:57:16 -0800811 if (SandboxingType == ST_NaCl) {
John Portoc39ec102015-12-01 13:00:43 -0800812 return;
813 }
814 static constexpr SizeT MaxArgs = 0;
Karl Schimpf20070e82016-03-17 13:30:13 -0700815 Operand *TargetHelper =
816 SandboxingType == ST_Nonsfi
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700817 ? Ctx->getConstantExternSym(
818 Ctx->getGlobalString("__aeabi_read_tp"))
Karl Schimpf20070e82016-03-17 13:30:13 -0700819 : Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_read_tp);
John Porto1d937a82015-12-17 06:19:34 -0800820 Context.insert<InstCall>(MaxArgs, Dest, TargetHelper, NoTailCall,
821 IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800822 Instr->setDeleted();
823 return;
824 }
825 case Intrinsics::Setjmp: {
826 static constexpr SizeT MaxArgs = 1;
Karl Schimpf20070e82016-03-17 13:30:13 -0700827 Operand *TargetHelper =
828 Ctx->getRuntimeHelperFunc(RuntimeHelper::H_call_setjmp);
John Porto1d937a82015-12-17 06:19:34 -0800829 auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
830 NoTailCall, IsTargetHelperCall);
John Portoc39ec102015-12-01 13:00:43 -0800831 Call->addArg(IntrinsicCall->getArg(0));
John Portoc39ec102015-12-01 13:00:43 -0800832 Instr->setDeleted();
833 return;
834 }
835 }
836 llvm::report_fatal_error("Control flow should never have reached here.");
837 }
838 }
839}
840
John Portof4198542015-11-20 14:17:23 -0800841void TargetARM32::findMaxStackOutArgsSize() {
John Porto614140e2015-11-23 11:43:13 -0800842 // MinNeededOutArgsBytes should be updated if the Target ever creates a
John Portof4198542015-11-20 14:17:23 -0800843 // high-level InstCall that requires more stack bytes.
844 constexpr size_t MinNeededOutArgsBytes = 0;
845 MaxOutArgsSizeBytes = MinNeededOutArgsBytes;
846 for (CfgNode *Node : Func->getNodes()) {
847 Context.init(Node);
848 while (!Context.atEnd()) {
849 PostIncrLoweringContext PostIncrement(Context);
Jim Stichnothf5fdd232016-05-09 12:24:36 -0700850 Inst *CurInstr = iteratorToInst(Context.getCur());
John Portof4198542015-11-20 14:17:23 -0800851 if (auto *Call = llvm::dyn_cast<InstCall>(CurInstr)) {
852 SizeT OutArgsSizeBytes = getCallStackArgumentsSizeBytes(Call);
853 MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, OutArgsSizeBytes);
854 }
855 }
856 }
857}
858
John Portodc619252016-02-10 15:57:16 -0800859void TargetARM32::createGotPtr() {
860 if (SandboxingType != ST_Nonsfi) {
861 return;
862 }
863 GotPtr = Func->makeVariable(IceType_i32);
864}
865
866void TargetARM32::insertGotPtrInitPlaceholder() {
867 if (SandboxingType != ST_Nonsfi) {
868 return;
869 }
870 assert(GotPtr != nullptr);
871 // We add the two placeholder instructions here. The first fakedefs T, an
872 // infinite-weight temporary, while the second fakedefs the GotPtr "using" T.
873 // This is needed because the GotPtr initialization, if needed, will require
874 // a register:
875 //
876 // movw reg, _GLOBAL_OFFSET_TABLE_ - 16 - .
877 // movt reg, _GLOBAL_OFFSET_TABLE_ - 12 - .
878 // add reg, pc, reg
879 // mov GotPtr, reg
880 //
881 // If GotPtr is not used, then both these pseudo-instructions are dce'd.
882 Variable *T = makeReg(IceType_i32);
883 Context.insert<InstFakeDef>(T);
884 Context.insert<InstFakeDef>(GotPtr, T);
885}
886
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700887GlobalString
888TargetARM32::createGotoffRelocation(const ConstantRelocatable *CR) {
889 GlobalString CRName = CR->getName();
890 GlobalString CRGotoffName =
891 Ctx->getGlobalString("GOTOFF$" + Func->getFunctionName() + "$" + CRName);
John Portodc619252016-02-10 15:57:16 -0800892 if (KnownGotoffs.count(CRGotoffName) == 0) {
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800893 constexpr bool SuppressMangling = true;
John Portoa78e4ba2016-03-15 09:28:04 -0700894 auto *Global =
895 VariableDeclaration::create(Func->getGlobalPool(), SuppressMangling);
John Portodc619252016-02-10 15:57:16 -0800896 Global->setIsConstant(true);
897 Global->setName(CRName);
John Portoa78e4ba2016-03-15 09:28:04 -0700898 Func->getGlobalPool()->willNotBeEmitted(Global);
John Portodc619252016-02-10 15:57:16 -0800899
John Portoa78e4ba2016-03-15 09:28:04 -0700900 auto *Gotoff =
901 VariableDeclaration::create(Func->getGlobalPool(), SuppressMangling);
John Portodc619252016-02-10 15:57:16 -0800902 constexpr auto GotFixup = R_ARM_GOTOFF32;
903 Gotoff->setIsConstant(true);
John Portodc619252016-02-10 15:57:16 -0800904 Gotoff->addInitializer(VariableDeclaration::RelocInitializer::create(
John Portoa78e4ba2016-03-15 09:28:04 -0700905 Func->getGlobalPool(), Global, {RelocOffset::create(Ctx, 0)},
906 GotFixup));
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800907 Gotoff->setName(CRGotoffName);
John Portodc619252016-02-10 15:57:16 -0800908 Func->addGlobal(Gotoff);
909 KnownGotoffs.emplace(CRGotoffName);
910 }
911 return CRGotoffName;
912}
913
914void TargetARM32::materializeGotAddr(CfgNode *Node) {
915 if (SandboxingType != ST_Nonsfi) {
916 return;
917 }
918
919 // At first, we try to find the
920 // GotPtr = def T
921 // pseudo-instruction that we placed for defining the got ptr. That
922 // instruction is not just a place-holder for defining the GotPtr (thus
923 // keeping liveness consistent), but it is also located at a point where it is
924 // safe to materialize the got addr -- i.e., before loading parameters to
925 // registers, but after moving register parameters from their home location.
926 InstFakeDef *DefGotPtr = nullptr;
927 for (auto &Inst : Node->getInsts()) {
928 auto *FakeDef = llvm::dyn_cast<InstFakeDef>(&Inst);
929 if (FakeDef != nullptr && FakeDef->getDest() == GotPtr) {
930 DefGotPtr = FakeDef;
931 break;
932 }
933 }
934
935 if (DefGotPtr == nullptr || DefGotPtr->isDeleted()) {
936 return;
937 }
938
939 // The got addr needs to be materialized at the same point where DefGotPtr
940 // lives.
Jim Stichnothf5fdd232016-05-09 12:24:36 -0700941 Context.setInsertPoint(instToIterator(DefGotPtr));
John Portodc619252016-02-10 15:57:16 -0800942 assert(DefGotPtr->getSrcSize() == 1);
943 auto *T = llvm::cast<Variable>(DefGotPtr->getSrc(0));
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700944 loadNamedConstantRelocatablePIC(Ctx->getGlobalString(GlobalOffsetTable), T,
John Portodc619252016-02-10 15:57:16 -0800945 [this, T](Variable *PC) { _add(T, PC, T); });
946 _mov(GotPtr, T);
947 DefGotPtr->setDeleted();
948}
949
950void TargetARM32::loadNamedConstantRelocatablePIC(
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700951 GlobalString Name, Variable *Register,
Jim Stichnoth98ba0062016-03-07 09:26:22 -0800952 std::function<void(Variable *PC)> Finish) {
John Portodc619252016-02-10 15:57:16 -0800953 assert(SandboxingType == ST_Nonsfi);
954 // We makeReg() here instead of getPhysicalRegister() because the latter ends
955 // up creating multi-blocks temporaries that liveness fails to validate.
956 auto *PC = makeReg(IceType_i32, RegARM32::Reg_pc);
957
958 auto *AddPcReloc = RelocOffset::create(Ctx);
959 AddPcReloc->setSubtract(true);
960 auto *AddPcLabel = InstARM32Label::create(Func, this);
961 AddPcLabel->setRelocOffset(AddPcReloc);
962
John Portodc619252016-02-10 15:57:16 -0800963 auto *MovwReloc = RelocOffset::create(Ctx);
964 auto *MovwLabel = InstARM32Label::create(Func, this);
965 MovwLabel->setRelocOffset(MovwReloc);
966
967 auto *MovtReloc = RelocOffset::create(Ctx);
968 auto *MovtLabel = InstARM32Label::create(Func, this);
969 MovtLabel->setRelocOffset(MovtReloc);
970
971 // The EmitString for these constant relocatables have hardcoded offsets
972 // attached to them. This could be dangerous if, e.g., we ever implemented
973 // instruction scheduling but llvm-mc currently does not support
974 //
975 // movw reg, #:lower16:(Symbol - Label - Number)
976 // movt reg, #:upper16:(Symbol - Label - Number)
977 //
978 // relocations.
John Portoe82b5602016-02-24 15:58:55 -0800979 static constexpr RelocOffsetT PcOffset = -8;
Jim Stichnoth467ffe52016-03-29 15:01:06 -0700980 auto *CRLower = Ctx->getConstantSymWithEmitString(
981 PcOffset, {MovwReloc, AddPcReloc}, Name, Name + " -16");
982 auto *CRUpper = Ctx->getConstantSymWithEmitString(
983 PcOffset, {MovtReloc, AddPcReloc}, Name, Name + " -12");
John Portodc619252016-02-10 15:57:16 -0800984
985 Context.insert(MovwLabel);
986 _movw(Register, CRLower);
987 Context.insert(MovtLabel);
988 _movt(Register, CRUpper);
989 // PC = fake-def to keep liveness consistent.
990 Context.insert<InstFakeDef>(PC);
991 Context.insert(AddPcLabel);
992 Finish(PC);
993}
994
Jan Voungb36ad9b2015-04-21 17:01:49 -0700995void TargetARM32::translateO2() {
996 TimerMarker T(TimerStack::TT_O2, Func);
997
John Portodc619252016-02-10 15:57:16 -0800998 // TODO(stichnot): share passes with other targets?
Jan Voungb36ad9b2015-04-21 17:01:49 -0700999 // https://code.google.com/p/nativeclient/issues/detail?id=4094
John Portodc619252016-02-10 15:57:16 -08001000 if (SandboxingType == ST_Nonsfi) {
1001 createGotPtr();
1002 }
John Porto5e0a8a72015-11-20 13:50:36 -08001003 genTargetHelperCalls();
John Portof4198542015-11-20 14:17:23 -08001004 findMaxStackOutArgsSize();
Jan Voungb36ad9b2015-04-21 17:01:49 -07001005
David Sehr4318a412015-11-11 15:01:55 -08001006 // Do not merge Alloca instructions, and lay out the stack.
John Porto614140e2015-11-23 11:43:13 -08001007 static constexpr bool SortAndCombineAllocas = true;
David Sehr4318a412015-11-11 15:01:55 -08001008 Func->processAllocas(SortAndCombineAllocas);
1009 Func->dump("After Alloca processing");
1010
Karl Schimpfd4699942016-04-02 09:55:31 -07001011 if (!getFlags().getEnablePhiEdgeSplit()) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07001012 // Lower Phi instructions.
1013 Func->placePhiLoads();
1014 if (Func->hasError())
1015 return;
1016 Func->placePhiStores();
1017 if (Func->hasError())
1018 return;
1019 Func->deletePhis();
1020 if (Func->hasError())
1021 return;
1022 Func->dump("After Phi lowering");
1023 }
1024
1025 // Address mode optimization.
1026 Func->getVMetadata()->init(VMK_SingleDefs);
1027 Func->doAddressOpt();
John Portoa47c11c2016-04-21 05:53:42 -07001028 Func->materializeVectorShuffles();
Jan Voungb36ad9b2015-04-21 17:01:49 -07001029
1030 // Argument lowering
1031 Func->doArgLowering();
1032
Andrew Scull57e12682015-09-16 11:30:19 -07001033 // Target lowering. This requires liveness analysis for some parts of the
1034 // lowering decisions, such as compare/branch fusing. If non-lightweight
1035 // liveness analysis is used, the instructions need to be renumbered first.
1036 // TODO: This renumbering should only be necessary if we're actually
1037 // calculating live intervals, which we only do for register allocation.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001038 Func->renumberInstructions();
1039 if (Func->hasError())
1040 return;
1041
Andrew Scull57e12682015-09-16 11:30:19 -07001042 // TODO: It should be sufficient to use the fastest liveness calculation,
1043 // i.e. livenessLightweight(). However, for some reason that slows down the
1044 // rest of the translation. Investigate.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001045 Func->liveness(Liveness_Basic);
1046 if (Func->hasError())
1047 return;
1048 Func->dump("After ARM32 address mode opt");
1049
John Portodc619252016-02-10 15:57:16 -08001050 if (SandboxingType == ST_Nonsfi) {
1051 insertGotPtrInitPlaceholder();
1052 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001053 Func->genCode();
1054 if (Func->hasError())
1055 return;
1056 Func->dump("After ARM32 codegen");
1057
Andrew Scull57e12682015-09-16 11:30:19 -07001058 // Register allocation. This requires instruction renumbering and full
1059 // liveness analysis.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001060 Func->renumberInstructions();
1061 if (Func->hasError())
1062 return;
1063 Func->liveness(Liveness_Intervals);
1064 if (Func->hasError())
1065 return;
Andrew Scull57e12682015-09-16 11:30:19 -07001066 // The post-codegen dump is done here, after liveness analysis and associated
1067 // cleanup, to make the dump cleaner and more useful.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001068 Func->dump("After initial ARM32 codegen");
Jim Stichnoth2943d772016-06-21 11:22:17 -07001069 // Validate the live range computations. The expensive validation call is
1070 // deliberately only made when assertions are enabled.
1071 assert(Func->validateLiveness());
Jan Voungb36ad9b2015-04-21 17:01:49 -07001072 Func->getVMetadata()->init(VMK_All);
1073 regAlloc(RAK_Global);
1074 if (Func->hasError())
1075 return;
John Porto614140e2015-11-23 11:43:13 -08001076
John Porto578f1162015-10-06 06:54:42 -07001077 copyRegAllocFromInfWeightVariable64On32(Func->getVariables());
Jan Voungb36ad9b2015-04-21 17:01:49 -07001078 Func->dump("After linear scan regalloc");
1079
Karl Schimpfd4699942016-04-02 09:55:31 -07001080 if (getFlags().getEnablePhiEdgeSplit()) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07001081 Func->advancedPhiLowering();
1082 Func->dump("After advanced Phi lowering");
1083 }
1084
John Porto614140e2015-11-23 11:43:13 -08001085 ForbidTemporaryWithoutReg _(this);
1086
Jan Voungb36ad9b2015-04-21 17:01:49 -07001087 // Stack frame mapping.
1088 Func->genFrame();
1089 if (Func->hasError())
1090 return;
1091 Func->dump("After stack frame mapping");
1092
John Porto866b6b12015-12-03 09:45:31 -08001093 postLowerLegalization();
Jan Voung28068ad2015-07-31 12:58:46 -07001094 if (Func->hasError())
1095 return;
John Porto866b6b12015-12-03 09:45:31 -08001096 Func->dump("After postLowerLegalization");
Jan Voung28068ad2015-07-31 12:58:46 -07001097
Jan Voungb36ad9b2015-04-21 17:01:49 -07001098 Func->contractEmptyNodes();
1099 Func->reorderNodes();
1100
Andrew Scull57e12682015-09-16 11:30:19 -07001101 // Branch optimization. This needs to be done just before code emission. In
1102 // particular, no transformations that insert or reorder CfgNodes should be
1103 // done after branch optimization. We go ahead and do it before nop insertion
1104 // to reduce the amount of work needed for searching for opportunities.
Jan Voungb36ad9b2015-04-21 17:01:49 -07001105 Func->doBranchOpt();
1106 Func->dump("After branch optimization");
1107
1108 // Nop insertion
Karl Schimpfd4699942016-04-02 09:55:31 -07001109 if (getFlags().getShouldDoNopInsertion()) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07001110 Func->doNopInsertion();
1111 }
1112}
1113
1114void TargetARM32::translateOm1() {
1115 TimerMarker T(TimerStack::TT_Om1, Func);
1116
John Portodc619252016-02-10 15:57:16 -08001117 // TODO(stichnot): share passes with other targets?
1118 if (SandboxingType == ST_Nonsfi) {
1119 createGotPtr();
1120 }
1121
John Porto5e0a8a72015-11-20 13:50:36 -08001122 genTargetHelperCalls();
John Portof4198542015-11-20 14:17:23 -08001123 findMaxStackOutArgsSize();
Jan Voungb36ad9b2015-04-21 17:01:49 -07001124
David Sehr4318a412015-11-11 15:01:55 -08001125 // Do not merge Alloca instructions, and lay out the stack.
John Porto614140e2015-11-23 11:43:13 -08001126 static constexpr bool DontSortAndCombineAllocas = false;
1127 Func->processAllocas(DontSortAndCombineAllocas);
David Sehr4318a412015-11-11 15:01:55 -08001128 Func->dump("After Alloca processing");
1129
Jan Voungb36ad9b2015-04-21 17:01:49 -07001130 Func->placePhiLoads();
1131 if (Func->hasError())
1132 return;
1133 Func->placePhiStores();
1134 if (Func->hasError())
1135 return;
1136 Func->deletePhis();
1137 if (Func->hasError())
1138 return;
1139 Func->dump("After Phi lowering");
1140
1141 Func->doArgLowering();
1142
John Portodc619252016-02-10 15:57:16 -08001143 if (SandboxingType == ST_Nonsfi) {
1144 insertGotPtrInitPlaceholder();
1145 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001146 Func->genCode();
1147 if (Func->hasError())
1148 return;
1149 Func->dump("After initial ARM32 codegen");
1150
1151 regAlloc(RAK_InfOnly);
1152 if (Func->hasError())
1153 return;
John Porto614140e2015-11-23 11:43:13 -08001154
John Porto578f1162015-10-06 06:54:42 -07001155 copyRegAllocFromInfWeightVariable64On32(Func->getVariables());
Jan Voungb36ad9b2015-04-21 17:01:49 -07001156 Func->dump("After regalloc of infinite-weight variables");
1157
John Porto614140e2015-11-23 11:43:13 -08001158 ForbidTemporaryWithoutReg _(this);
1159
Jan Voungb36ad9b2015-04-21 17:01:49 -07001160 Func->genFrame();
1161 if (Func->hasError())
1162 return;
1163 Func->dump("After stack frame mapping");
1164
John Porto866b6b12015-12-03 09:45:31 -08001165 postLowerLegalization();
Jan Voung28068ad2015-07-31 12:58:46 -07001166 if (Func->hasError())
1167 return;
John Porto866b6b12015-12-03 09:45:31 -08001168 Func->dump("After postLowerLegalization");
Jan Voung28068ad2015-07-31 12:58:46 -07001169
Jan Voungb36ad9b2015-04-21 17:01:49 -07001170 // Nop insertion
Karl Schimpfd4699942016-04-02 09:55:31 -07001171 if (getFlags().getShouldDoNopInsertion()) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07001172 Func->doNopInsertion();
1173 }
1174}
1175
David Sehre39d0ca2015-11-06 11:25:41 -08001176uint32_t TargetARM32::getStackAlignment() const {
1177 return ARM32_STACK_ALIGNMENT_BYTES;
1178}
1179
Jan Voungb36ad9b2015-04-21 17:01:49 -07001180bool TargetARM32::doBranchOpt(Inst *I, const CfgNode *NextNode) {
Jim Stichnoth54f3d512015-12-11 09:53:00 -08001181 if (auto *Br = llvm::dyn_cast<InstARM32Br>(I)) {
Jan Voung3bfd99a2015-05-22 16:35:25 -07001182 return Br->optimizeBranch(NextNode);
1183 }
Jan Voungb2d50842015-05-12 09:53:50 -07001184 return false;
Jan Voungb36ad9b2015-04-21 17:01:49 -07001185}
1186
Jim Stichnoth467ffe52016-03-29 15:01:06 -07001187const char *TargetARM32::getRegName(RegNumT RegNum, Type Ty) const {
Karl Schimpf7cb2db32015-10-29 14:04:12 -07001188 (void)Ty;
John Porto149999e2016-01-04 13:45:26 -08001189 return RegARM32::getRegName(RegNum);
Jan Voungb36ad9b2015-04-21 17:01:49 -07001190}
1191
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001192Variable *TargetARM32::getPhysicalRegister(RegNumT RegNum, Type Ty) {
John Portoba6a67c2015-09-25 15:19:45 -07001193 static const Type DefaultType[] = {
John Porto2187c842015-12-16 07:48:25 -08001194#define X(val, encode, name, cc_arg, scratch, preserved, stackptr, frameptr, \
John Portodff7dbd2016-01-04 09:49:55 -08001195 isGPR, isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init) \
John Portoba6a67c2015-09-25 15:19:45 -07001196 (isFP32) \
1197 ? IceType_f32 \
1198 : ((isFP64) ? IceType_f64 : ((isVec128 ? IceType_v4i32 : IceType_i32))),
1199 REGARM32_TABLE
1200#undef X
1201 };
1202
John Portoba6a67c2015-09-25 15:19:45 -07001203 if (Ty == IceType_void) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001204 assert(unsigned(RegNum) < llvm::array_lengthof(DefaultType));
John Portoba6a67c2015-09-25 15:19:45 -07001205 Ty = DefaultType[RegNum];
1206 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001207 if (PhysicalRegisters[Ty].empty())
1208 PhysicalRegisters[Ty].resize(RegARM32::Reg_NUM);
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001209 assert(unsigned(RegNum) < PhysicalRegisters[Ty].size());
Jan Voungb36ad9b2015-04-21 17:01:49 -07001210 Variable *Reg = PhysicalRegisters[Ty][RegNum];
1211 if (Reg == nullptr) {
1212 Reg = Func->makeVariable(Ty);
1213 Reg->setRegNum(RegNum);
1214 PhysicalRegisters[Ty][RegNum] = Reg;
Jim Stichnoth69660552015-09-18 06:41:02 -07001215 // Specially mark a named physical register as an "argument" so that it is
1216 // considered live upon function entry. Otherwise it's possible to get
1217 // liveness validation errors for saving callee-save registers.
1218 Func->addImplicitArg(Reg);
1219 // Don't bother tracking the live range of a named physical register.
1220 Reg->setIgnoreLiveness();
Jan Voungb36ad9b2015-04-21 17:01:49 -07001221 }
1222 return Reg;
1223}
1224
Andrew Scull86df4e92015-07-30 13:54:44 -07001225void TargetARM32::emitJumpTable(const Cfg *Func,
1226 const InstJumpTable *JumpTable) const {
Karl Schimpfd4699942016-04-02 09:55:31 -07001227 (void)Func;
Andrew Scull86df4e92015-07-30 13:54:44 -07001228 (void)JumpTable;
Karl Schimpfd4699942016-04-02 09:55:31 -07001229 UnimplementedError(getFlags());
Andrew Scull86df4e92015-07-30 13:54:44 -07001230}
1231
Jan Voungb36ad9b2015-04-21 17:01:49 -07001232void TargetARM32::emitVariable(const Variable *Var) const {
Jan Voung28068ad2015-07-31 12:58:46 -07001233 if (!BuildDefs::dump())
1234 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07001235 Ostream &Str = Ctx->getStrEmit();
Jan Voungb2d50842015-05-12 09:53:50 -07001236 if (Var->hasReg()) {
1237 Str << getRegName(Var->getRegNum(), Var->getType());
1238 return;
1239 }
Andrew Scull11c9a322015-08-28 14:24:14 -07001240 if (Var->mustHaveReg()) {
Jim Stichnotha91c3412016-04-05 15:31:43 -07001241 llvm::report_fatal_error("Infinite-weight Variable (" + Var->getName() +
Jim Stichnoth45bec542016-02-05 10:26:09 -08001242 ") has no register assigned - function " +
1243 Func->getFunctionName());
Jan Voungb2d50842015-05-12 09:53:50 -07001244 }
John Porto614140e2015-11-23 11:43:13 -08001245 assert(!Var->isRematerializable());
Jan Voungb2d50842015-05-12 09:53:50 -07001246 int32_t Offset = Var->getStackOffset();
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001247 auto BaseRegNum = Var->getBaseRegNum();
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08001248 if (BaseRegNum.hasNoValue()) {
Jan Voung28068ad2015-07-31 12:58:46 -07001249 BaseRegNum = getFrameOrStackReg();
Jan Voung28068ad2015-07-31 12:58:46 -07001250 }
John Portoba6a67c2015-09-25 15:19:45 -07001251 const Type VarTy = Var->getType();
John Portoba6a67c2015-09-25 15:19:45 -07001252 Str << "[" << getRegName(BaseRegNum, VarTy);
Jan Voungb3401d22015-05-18 09:38:21 -07001253 if (Offset != 0) {
Jim Stichnoth8ff4b282016-01-04 15:39:06 -08001254 Str << ", #" << Offset;
Jan Voungb3401d22015-05-18 09:38:21 -07001255 }
1256 Str << "]";
Jan Voungb36ad9b2015-04-21 17:01:49 -07001257}
1258
John Porto2187c842015-12-16 07:48:25 -08001259TargetARM32::CallingConv::CallingConv()
1260 : GPRegsUsed(RegARM32::Reg_NUM),
1261 GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()),
1262 I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()),
1263 VFPRegsUsed(RegARM32::Reg_NUM),
1264 FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()),
1265 FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()),
1266 Vec128Args(Vec128ArgInitializer.rbegin(), Vec128ArgInitializer.rend()) {}
Jan Voungb0a8c242015-06-18 15:00:14 -07001267
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001268bool TargetARM32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) {
1269 CfgVector<RegNumT> *Source;
Jan Voungb0a8c242015-06-18 15:00:14 -07001270
John Porto2187c842015-12-16 07:48:25 -08001271 switch (Ty) {
1272 default: {
1273 assert(isScalarIntegerType(Ty));
1274 Source = &GPRArgs;
1275 } break;
1276 case IceType_i64: {
1277 Source = &I64Args;
1278 } break;
1279 }
John Portoeb13acc2015-12-09 05:10:58 -08001280
John Porto2187c842015-12-16 07:48:25 -08001281 discardUnavailableGPRsAndTheirAliases(Source);
1282
1283 if (Source->empty()) {
1284 GPRegsUsed.set();
Jan Voung86ebec12015-08-09 07:58:35 -07001285 return false;
John Porto385351b2015-09-16 16:11:10 -07001286 }
1287
John Porto2187c842015-12-16 07:48:25 -08001288 *Reg = Source->back();
1289 // Note that we don't Source->pop_back() here. This is intentional. Notice how
1290 // we mark all of Reg's aliases as Used. So, for the next argument,
1291 // Source->back() is marked as unavailable, and it is thus implicitly popped
1292 // from the stack.
1293 GPRegsUsed |= RegisterAliases[*Reg];
1294 return true;
1295}
1296
1297// GPR are not packed when passing parameters. Thus, a function foo(i32, i64,
1298// i32) will have the first argument in r0, the second in r1-r2, and the third
1299// on the stack. To model this behavior, whenever we pop a register from Regs,
1300// we remove all of its aliases from the pool of available GPRs. This has the
1301// effect of computing the "closure" on the GPR registers.
1302void TargetARM32::CallingConv::discardUnavailableGPRsAndTheirAliases(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001303 CfgVector<RegNumT> *Regs) {
John Porto2187c842015-12-16 07:48:25 -08001304 while (!Regs->empty() && GPRegsUsed[Regs->back()]) {
1305 GPRegsUsed |= RegisterAliases[Regs->back()];
1306 Regs->pop_back();
1307 }
1308}
1309
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001310bool TargetARM32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) {
1311 CfgVector<RegNumT> *Source;
John Porto2187c842015-12-16 07:48:25 -08001312
1313 switch (Ty) {
1314 default: {
1315 assert(isVectorType(Ty));
1316 Source = &Vec128Args;
1317 } break;
1318 case IceType_f32: {
1319 Source = &FP32Args;
1320 } break;
1321 case IceType_f64: {
1322 Source = &FP64Args;
1323 } break;
Jan Voung86ebec12015-08-09 07:58:35 -07001324 }
John Porto385351b2015-09-16 16:11:10 -07001325
John Porto2187c842015-12-16 07:48:25 -08001326 discardUnavailableVFPRegs(Source);
1327
1328 if (Source->empty()) {
1329 VFPRegsUsed.set();
1330 return false;
1331 }
1332
1333 *Reg = Source->back();
1334 VFPRegsUsed |= RegisterAliases[*Reg];
1335 return true;
1336}
1337
1338// Arguments in VFP registers are not packed, so we don't mark the popped
1339// registers' aliases as unavailable.
1340void TargetARM32::CallingConv::discardUnavailableVFPRegs(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001341 CfgVector<RegNumT> *Regs) {
John Porto2187c842015-12-16 07:48:25 -08001342 while (!Regs->empty() && VFPRegsUsed[Regs->back()]) {
1343 Regs->pop_back();
1344 }
Jan Voung86ebec12015-08-09 07:58:35 -07001345}
1346
Jan Voungb36ad9b2015-04-21 17:01:49 -07001347void TargetARM32::lowerArguments() {
Jan Voungb3401d22015-05-18 09:38:21 -07001348 VarList &Args = Func->getArgs();
Jan Voungb0a8c242015-06-18 15:00:14 -07001349 TargetARM32::CallingConv CC;
Jan Voungb3401d22015-05-18 09:38:21 -07001350
Andrew Scull57e12682015-09-16 11:30:19 -07001351 // For each register argument, replace Arg in the argument list with the home
1352 // register. Then generate an instruction in the prolog to copy the home
1353 // register to the assigned location of Arg.
Jan Voungb3401d22015-05-18 09:38:21 -07001354 Context.init(Func->getEntryNode());
1355 Context.setInsertPoint(Context.getCur());
1356
1357 for (SizeT I = 0, E = Args.size(); I < E; ++I) {
1358 Variable *Arg = Args[I];
1359 Type Ty = Arg->getType();
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001360 RegNumT RegNum;
John Porto2187c842015-12-16 07:48:25 -08001361 if (isScalarIntegerType(Ty)) {
1362 if (!CC.argInGPR(Ty, &RegNum)) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001363 continue;
John Porto2187c842015-12-16 07:48:25 -08001364 }
Jan Voungb3401d22015-05-18 09:38:21 -07001365 } else {
John Porto2187c842015-12-16 07:48:25 -08001366 if (!CC.argInVFP(Ty, &RegNum)) {
1367 continue;
Jan Voung86ebec12015-08-09 07:58:35 -07001368 }
Jan Voungb3401d22015-05-18 09:38:21 -07001369 }
John Porto2187c842015-12-16 07:48:25 -08001370
1371 Variable *RegisterArg = Func->makeVariable(Ty);
1372 if (BuildDefs::dump()) {
Jim Stichnotha91c3412016-04-05 15:31:43 -07001373 RegisterArg->setName(Func, "home_reg:" + Arg->getName());
John Porto2187c842015-12-16 07:48:25 -08001374 }
1375 RegisterArg->setIsArg();
1376 Arg->setIsArg(false);
1377 Args[I] = RegisterArg;
1378 switch (Ty) {
1379 default: { RegisterArg->setRegNum(RegNum); } break;
1380 case IceType_i64: {
1381 auto *RegisterArg64 = llvm::cast<Variable64On32>(RegisterArg);
1382 RegisterArg64->initHiLo(Func);
1383 RegisterArg64->getLo()->setRegNum(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001384 RegNumT::fixme(RegARM32::getI64PairFirstGPRNum(RegNum)));
John Porto2187c842015-12-16 07:48:25 -08001385 RegisterArg64->getHi()->setRegNum(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001386 RegNumT::fixme(RegARM32::getI64PairSecondGPRNum(RegNum)));
John Porto2187c842015-12-16 07:48:25 -08001387 } break;
1388 }
John Porto1d937a82015-12-17 06:19:34 -08001389 Context.insert<InstAssign>(Arg, RegisterArg);
Jan Voungb3401d22015-05-18 09:38:21 -07001390 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001391}
1392
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001393// Helper function for addProlog().
1394//
Andrew Scull57e12682015-09-16 11:30:19 -07001395// This assumes Arg is an argument passed on the stack. This sets the frame
1396// offset for Arg and updates InArgsSizeBytes according to Arg's width. For an
1397// I64 arg that has been split into Lo and Hi components, it calls itself
1398// recursively on the components, taking care to handle Lo first because of the
1399// little-endian architecture. Lastly, this function generates an instruction
1400// to copy Arg into its assigned register if applicable.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001401void TargetARM32::finishArgumentLowering(Variable *Arg, Variable *FramePtr,
1402 size_t BasicFrameOffset,
John Porto3f6b47d2015-11-19 05:42:59 -08001403 size_t *InArgsSizeBytes) {
John Porto324334e2016-03-08 11:00:53 -08001404 const Type Ty = Arg->getType();
1405 *InArgsSizeBytes = applyStackAlignmentTy(*InArgsSizeBytes, Ty);
1406
Andrew Scull6d47bcd2015-09-17 17:10:05 -07001407 if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) {
John Porto324334e2016-03-08 11:00:53 -08001408 Variable *const Lo = Arg64On32->getLo();
1409 Variable *const Hi = Arg64On32->getHi();
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001410 finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, InArgsSizeBytes);
1411 finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, InArgsSizeBytes);
1412 return;
1413 }
John Porto3f6b47d2015-11-19 05:42:59 -08001414 assert(Ty != IceType_i64);
1415
John Porto3f6b47d2015-11-19 05:42:59 -08001416 const int32_t ArgStackOffset = BasicFrameOffset + *InArgsSizeBytes;
1417 *InArgsSizeBytes += typeWidthInBytesOnStack(Ty);
1418
1419 if (!Arg->hasReg()) {
1420 Arg->setStackOffset(ArgStackOffset);
1421 return;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001422 }
John Porto3f6b47d2015-11-19 05:42:59 -08001423
1424 // If the argument variable has been assigned a register, we need to copy the
1425 // value from the stack slot.
1426 Variable *Parameter = Func->makeVariable(Ty);
1427 Parameter->setMustNotHaveReg();
1428 Parameter->setStackOffset(ArgStackOffset);
1429 _mov(Arg, Parameter);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001430}
1431
Jan Voungb36ad9b2015-04-21 17:01:49 -07001432Type TargetARM32::stackSlotType() { return IceType_i32; }
1433
1434void TargetARM32::addProlog(CfgNode *Node) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001435 // Stack frame layout:
1436 //
1437 // +------------------------+
1438 // | 1. preserved registers |
1439 // +------------------------+
1440 // | 2. padding |
Jan Voung28068ad2015-07-31 12:58:46 -07001441 // +------------------------+ <--- FramePointer (if used)
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001442 // | 3. global spill area |
1443 // +------------------------+
1444 // | 4. padding |
1445 // +------------------------+
1446 // | 5. local spill area |
1447 // +------------------------+
1448 // | 6. padding |
1449 // +------------------------+
John Portof4198542015-11-20 14:17:23 -08001450 // | 7. allocas (variable) |
1451 // +------------------------+
1452 // | 8. padding |
1453 // +------------------------+
1454 // | 9. out args |
Jan Voung28068ad2015-07-31 12:58:46 -07001455 // +------------------------+ <--- StackPointer
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001456 //
1457 // The following variables record the size in bytes of the given areas:
1458 // * PreservedRegsSizeBytes: area 1
1459 // * SpillAreaPaddingBytes: area 2
1460 // * GlobalsSize: area 3
1461 // * GlobalsAndSubsequentPaddingSize: areas 3 - 4
1462 // * LocalsSpillAreaSize: area 5
John Portof4198542015-11-20 14:17:23 -08001463 // * SpillAreaSizeBytes: areas 2 - 6, and 9
1464 // * MaxOutArgsSizeBytes: area 9
1465 //
Andrew Scull57e12682015-09-16 11:30:19 -07001466 // Determine stack frame offsets for each Variable without a register
1467 // assignment. This can be done as one variable per stack slot. Or, do
1468 // coalescing by running the register allocator again with an infinite set of
1469 // registers (as a side effect, this gives variables a second chance at
1470 // physical register assignment).
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001471 //
Andrew Scull57e12682015-09-16 11:30:19 -07001472 // A middle ground approach is to leverage sparsity and allocate one block of
1473 // space on the frame for globals (variables with multi-block lifetime), and
1474 // one block to share for locals (single-block lifetime).
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001475
1476 Context.init(Node);
1477 Context.setInsertPoint(Context.getCur());
1478
John Portoe82b5602016-02-24 15:58:55 -08001479 SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None);
1480 RegsUsed = SmallBitVector(CalleeSaves.size());
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001481 VarList SortedSpilledVariables;
1482 size_t GlobalsSize = 0;
Andrew Scull57e12682015-09-16 11:30:19 -07001483 // If there is a separate locals area, this represents that area. Otherwise
1484 // it counts any variable not counted by GlobalsSize.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001485 SpillAreaSizeBytes = 0;
Andrew Scull57e12682015-09-16 11:30:19 -07001486 // If there is a separate locals area, this specifies the alignment for it.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001487 uint32_t LocalsSlotsAlignmentBytes = 0;
Andrew Scull57e12682015-09-16 11:30:19 -07001488 // The entire spill locations area gets aligned to largest natural alignment
1489 // of the variables that have a spill slot.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001490 uint32_t SpillAreaAlignmentBytes = 0;
1491 // For now, we don't have target-specific variables that need special
1492 // treatment (no stack-slot-linked SpillVariable type).
John Portoe0b829f2015-09-28 09:50:48 -07001493 std::function<bool(Variable *)> TargetVarHook = [](Variable *Var) {
1494 static constexpr bool AssignStackSlot = false;
1495 static constexpr bool DontAssignStackSlot = !AssignStackSlot;
1496 if (llvm::isa<Variable64On32>(Var)) {
1497 return DontAssignStackSlot;
1498 }
1499 return AssignStackSlot;
1500 };
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001501
1502 // Compute the list of spilled variables and bounds for GlobalsSize, etc.
1503 getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize,
1504 &SpillAreaSizeBytes, &SpillAreaAlignmentBytes,
1505 &LocalsSlotsAlignmentBytes, TargetVarHook);
1506 uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes;
1507 SpillAreaSizeBytes += GlobalsSize;
1508
Andrew Scull57e12682015-09-16 11:30:19 -07001509 // Add push instructions for preserved registers. On ARM, "push" can push a
1510 // whole list of GPRs via a bitmask (0-15). Unlike x86, ARM also has
John Portoeb13acc2015-12-09 05:10:58 -08001511 // callee-saved float/vector registers.
1512 //
1513 // The "vpush" instruction can handle a whole list of float/vector registers,
1514 // but it only handles contiguous sequences of registers by specifying the
1515 // start and the length.
1516 PreservedGPRs.reserve(CalleeSaves.size());
1517 PreservedSRegs.reserve(CalleeSaves.size());
1518
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001519 // Consider FP and LR as callee-save / used as needed.
1520 if (UsesFramePointer) {
John Portoeb13acc2015-12-09 05:10:58 -08001521 if (RegsUsed[RegARM32::Reg_fp]) {
1522 llvm::report_fatal_error("Frame pointer has been used.");
1523 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001524 CalleeSaves[RegARM32::Reg_fp] = true;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001525 RegsUsed[RegARM32::Reg_fp] = true;
1526 }
1527 if (!MaybeLeafFunc) {
1528 CalleeSaves[RegARM32::Reg_lr] = true;
1529 RegsUsed[RegARM32::Reg_lr] = true;
1530 }
John Portoeb13acc2015-12-09 05:10:58 -08001531
1532 // Make two passes over the used registers. The first pass records all the
1533 // used registers -- and their aliases. Then, we figure out which GPRs and
1534 // VFP S registers should be saved. We don't bother saving D/Q registers
1535 // because their uses are recorded as S regs uses.
John Portoe82b5602016-02-24 15:58:55 -08001536 SmallBitVector ToPreserve(RegARM32::Reg_NUM);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001537 for (SizeT i = 0; i < CalleeSaves.size(); ++i) {
John Portoeb13acc2015-12-09 05:10:58 -08001538 if (NeedSandboxing && i == RegARM32::Reg_r9) {
1539 // r9 is never updated in sandboxed code.
John Porto578f1162015-10-06 06:54:42 -07001540 continue;
1541 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001542 if (CalleeSaves[i] && RegsUsed[i]) {
John Portoeb13acc2015-12-09 05:10:58 -08001543 ToPreserve |= RegisterAliases[i];
1544 }
1545 }
1546
1547 uint32_t NumCallee = 0;
1548 size_t PreservedRegsSizeBytes = 0;
1549
1550 // RegClasses is a tuple of
1551 //
1552 // <First Register in Class, Last Register in Class, Vector of Save Registers>
1553 //
1554 // We use this tuple to figure out which register we should push/pop during
1555 // prolog/epilog.
1556 using RegClassType = std::tuple<uint32_t, uint32_t, VarList *>;
1557 const RegClassType RegClasses[] = {
1558 RegClassType(RegARM32::Reg_GPR_First, RegARM32::Reg_GPR_Last,
1559 &PreservedGPRs),
1560 RegClassType(RegARM32::Reg_SREG_First, RegARM32::Reg_SREG_Last,
1561 &PreservedSRegs)};
1562 for (const auto &RegClass : RegClasses) {
1563 const uint32_t FirstRegInClass = std::get<0>(RegClass);
1564 const uint32_t LastRegInClass = std::get<1>(RegClass);
1565 VarList *const PreservedRegsInClass = std::get<2>(RegClass);
1566 for (uint32_t Reg = FirstRegInClass; Reg <= LastRegInClass; ++Reg) {
1567 if (!ToPreserve[Reg]) {
John Porto52b51572015-12-05 14:16:25 -08001568 continue;
1569 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001570 ++NumCallee;
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001571 Variable *PhysicalRegister = getPhysicalRegister(RegNumT::fromInt(Reg));
John Portoafc92af2015-10-16 10:34:04 -07001572 PreservedRegsSizeBytes +=
1573 typeWidthInBytesOnStack(PhysicalRegister->getType());
John Portoeb13acc2015-12-09 05:10:58 -08001574 PreservedRegsInClass->push_back(PhysicalRegister);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001575 }
1576 }
John Portoeb13acc2015-12-09 05:10:58 -08001577
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001578 Ctx->statsUpdateRegistersSaved(NumCallee);
John Portoeb13acc2015-12-09 05:10:58 -08001579 if (!PreservedSRegs.empty())
1580 _push(PreservedSRegs);
1581 if (!PreservedGPRs.empty())
1582 _push(PreservedGPRs);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001583
1584 // Generate "mov FP, SP" if needed.
1585 if (UsesFramePointer) {
1586 Variable *FP = getPhysicalRegister(RegARM32::Reg_fp);
1587 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
1588 _mov(FP, SP);
1589 // Keep FP live for late-stage liveness analysis (e.g. asm-verbose mode).
John Porto1d937a82015-12-17 06:19:34 -08001590 Context.insert<InstFakeUse>(FP);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001591 }
1592
Andrew Scull57e12682015-09-16 11:30:19 -07001593 // Align the variables area. SpillAreaPaddingBytes is the size of the region
1594 // after the preserved registers and before the spill areas.
1595 // LocalsSlotsPaddingBytes is the amount of padding between the globals and
1596 // locals area if they are separate.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001597 assert(SpillAreaAlignmentBytes <= ARM32_STACK_ALIGNMENT_BYTES);
1598 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes);
1599 uint32_t SpillAreaPaddingBytes = 0;
1600 uint32_t LocalsSlotsPaddingBytes = 0;
1601 alignStackSpillAreas(PreservedRegsSizeBytes, SpillAreaAlignmentBytes,
1602 GlobalsSize, LocalsSlotsAlignmentBytes,
1603 &SpillAreaPaddingBytes, &LocalsSlotsPaddingBytes);
1604 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes;
1605 uint32_t GlobalsAndSubsequentPaddingSize =
1606 GlobalsSize + LocalsSlotsPaddingBytes;
1607
John Portof4198542015-11-20 14:17:23 -08001608 // Adds the out args space to the stack, and align SP if necessary.
John Portoeb13acc2015-12-09 05:10:58 -08001609 if (!NeedsStackAlignment) {
1610 SpillAreaSizeBytes += MaxOutArgsSizeBytes;
1611 } else {
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001612 uint32_t StackOffset = PreservedRegsSizeBytes;
1613 uint32_t StackSize = applyStackAlignment(StackOffset + SpillAreaSizeBytes);
John Portof4198542015-11-20 14:17:23 -08001614 StackSize = applyStackAlignment(StackSize + MaxOutArgsSizeBytes);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001615 SpillAreaSizeBytes = StackSize - StackOffset;
1616 }
1617
John Porto614140e2015-11-23 11:43:13 -08001618 // Combine fixed alloca with SpillAreaSize.
1619 SpillAreaSizeBytes += FixedAllocaSizeBytes;
1620
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001621 // Generate "sub sp, SpillAreaSizeBytes"
1622 if (SpillAreaSizeBytes) {
Jan Voung28068ad2015-07-31 12:58:46 -07001623 // Use the scratch register if needed to legalize the immediate.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001624 Operand *SubAmount = legalize(Ctx->getConstantInt32(SpillAreaSizeBytes),
Jan Voung28068ad2015-07-31 12:58:46 -07001625 Legal_Reg | Legal_Flex, getReservedTmpReg());
John Porto52b51572015-12-05 14:16:25 -08001626 Sandboxer(this).sub_sp(SubAmount);
John Porto614140e2015-11-23 11:43:13 -08001627 if (FixedAllocaAlignBytes > ARM32_STACK_ALIGNMENT_BYTES) {
John Porto52b51572015-12-05 14:16:25 -08001628 Sandboxer(this).align_sp(FixedAllocaAlignBytes);
John Porto614140e2015-11-23 11:43:13 -08001629 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001630 }
John Porto614140e2015-11-23 11:43:13 -08001631
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001632 Ctx->statsUpdateFrameBytes(SpillAreaSizeBytes);
1633
Andrew Scull57e12682015-09-16 11:30:19 -07001634 // Fill in stack offsets for stack args, and copy args into registers for
1635 // those that were register-allocated. Args are pushed right to left, so
1636 // Arg[0] is closest to the stack/frame pointer.
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001637 Variable *FramePtr = getPhysicalRegister(getFrameOrStackReg());
1638 size_t BasicFrameOffset = PreservedRegsSizeBytes;
1639 if (!UsesFramePointer)
1640 BasicFrameOffset += SpillAreaSizeBytes;
1641
John Portodc619252016-02-10 15:57:16 -08001642 materializeGotAddr(Node);
1643
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001644 const VarList &Args = Func->getArgs();
1645 size_t InArgsSizeBytes = 0;
Jan Voungb0a8c242015-06-18 15:00:14 -07001646 TargetARM32::CallingConv CC;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001647 for (Variable *Arg : Args) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001648 RegNumT DummyReg;
John Porto2187c842015-12-16 07:48:25 -08001649 const Type Ty = Arg->getType();
1650
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001651 // Skip arguments passed in registers.
John Porto2187c842015-12-16 07:48:25 -08001652 if (isScalarIntegerType(Ty)) {
1653 if (CC.argInGPR(Ty, &DummyReg)) {
1654 continue;
1655 }
Jan Voungb0a8c242015-06-18 15:00:14 -07001656 } else {
John Porto2187c842015-12-16 07:48:25 -08001657 if (CC.argInVFP(Ty, &DummyReg)) {
1658 continue;
1659 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001660 }
John Porto2187c842015-12-16 07:48:25 -08001661 finishArgumentLowering(Arg, FramePtr, BasicFrameOffset, &InArgsSizeBytes);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001662 }
1663
1664 // Fill in stack offsets for locals.
1665 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes,
1666 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize,
1667 UsesFramePointer);
1668 this->HasComputedFrame = true;
1669
Jim Stichnoth20b71f52015-06-24 15:52:24 -07001670 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) {
John Portof5f02f72015-11-09 14:52:40 -08001671 OstreamLocker _(Func->getContext());
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001672 Ostream &Str = Func->getContext()->getStrDump();
1673
1674 Str << "Stack layout:\n";
1675 uint32_t SPAdjustmentPaddingSize =
1676 SpillAreaSizeBytes - LocalsSpillAreaSize -
John Portof4198542015-11-20 14:17:23 -08001677 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes -
1678 MaxOutArgsSizeBytes;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001679 Str << " in-args = " << InArgsSizeBytes << " bytes\n"
1680 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n"
1681 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n"
1682 << " globals spill area = " << GlobalsSize << " bytes\n"
1683 << " globals-locals spill areas intermediate padding = "
1684 << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n"
1685 << " locals spill area = " << LocalsSpillAreaSize << " bytes\n"
1686 << " SP alignment padding = " << SPAdjustmentPaddingSize << " bytes\n";
1687
1688 Str << "Stack details:\n"
1689 << " SP adjustment = " << SpillAreaSizeBytes << " bytes\n"
1690 << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n"
John Portof4198542015-11-20 14:17:23 -08001691 << " outgoing args size = " << MaxOutArgsSizeBytes << " bytes\n"
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001692 << " locals spill area alignment = " << LocalsSlotsAlignmentBytes
1693 << " bytes\n"
1694 << " is FP based = " << UsesFramePointer << "\n";
1695 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07001696}
1697
1698void TargetARM32::addEpilog(CfgNode *Node) {
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001699 InstList &Insts = Node->getInsts();
1700 InstList::reverse_iterator RI, E;
1701 for (RI = Insts.rbegin(), E = Insts.rend(); RI != E; ++RI) {
1702 if (llvm::isa<InstARM32Ret>(*RI))
1703 break;
1704 }
1705 if (RI == E)
1706 return;
1707
Andrew Scull57e12682015-09-16 11:30:19 -07001708 // Convert the reverse_iterator position into its corresponding (forward)
1709 // iterator position.
Jim Stichnoth7c9728f2016-08-31 13:42:00 -07001710 InstList::iterator InsertPoint = reverseToForwardIterator(RI);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001711 --InsertPoint;
1712 Context.init(Node);
1713 Context.setInsertPoint(InsertPoint);
1714
1715 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
1716 if (UsesFramePointer) {
1717 Variable *FP = getPhysicalRegister(RegARM32::Reg_fp);
Andrew Scull57e12682015-09-16 11:30:19 -07001718 // For late-stage liveness analysis (e.g. asm-verbose mode), adding a fake
1719 // use of SP before the assignment of SP=FP keeps previous SP adjustments
1720 // from being dead-code eliminated.
John Porto1d937a82015-12-17 06:19:34 -08001721 Context.insert<InstFakeUse>(SP);
John Porto52b51572015-12-05 14:16:25 -08001722 Sandboxer(this).reset_sp(FP);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001723 } else {
1724 // add SP, SpillAreaSizeBytes
1725 if (SpillAreaSizeBytes) {
Jan Voung28068ad2015-07-31 12:58:46 -07001726 // Use the scratch register if needed to legalize the immediate.
1727 Operand *AddAmount =
1728 legalize(Ctx->getConstantInt32(SpillAreaSizeBytes),
1729 Legal_Reg | Legal_Flex, getReservedTmpReg());
John Porto52b51572015-12-05 14:16:25 -08001730 Sandboxer(this).add_sp(AddAmount);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001731 }
1732 }
1733
John Portoeb13acc2015-12-09 05:10:58 -08001734 if (!PreservedGPRs.empty())
1735 _pop(PreservedGPRs);
1736 if (!PreservedSRegs.empty())
1737 _pop(PreservedSRegs);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001738
Karl Schimpfd4699942016-04-02 09:55:31 -07001739 if (!getFlags().getUseSandboxing())
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001740 return;
1741
1742 // Change the original ret instruction into a sandboxed return sequence.
John Portoeb13acc2015-12-09 05:10:58 -08001743 //
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001744 // bundle_lock
1745 // bic lr, #0xc000000f
1746 // bx lr
1747 // bundle_unlock
John Portoeb13acc2015-12-09 05:10:58 -08001748 //
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001749 // This isn't just aligning to the getBundleAlignLog2Bytes(). It needs to
1750 // restrict to the lower 1GB as well.
John Porto52b51572015-12-05 14:16:25 -08001751 Variable *LR = getPhysicalRegister(RegARM32::Reg_lr);
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001752 Variable *RetValue = nullptr;
1753 if (RI->getSrcSize())
1754 RetValue = llvm::cast<Variable>(RI->getSrc(0));
John Porto52b51572015-12-05 14:16:25 -08001755
1756 Sandboxer(this).ret(LR, RetValue);
1757
Jan Voung0fa6c5a2015-06-01 11:04:04 -07001758 RI->setDeleted();
Jan Voungb36ad9b2015-04-21 17:01:49 -07001759}
1760
John Portof5f02f72015-11-09 14:52:40 -08001761bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const {
1762 constexpr bool ZeroExt = false;
1763 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset);
Jan Voung28068ad2015-07-31 12:58:46 -07001764}
1765
John Porto866b6b12015-12-03 09:45:31 -08001766Variable *TargetARM32::PostLoweringLegalizer::newBaseRegister(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001767 Variable *Base, int32_t Offset, RegNumT ScratchRegNum) {
Andrew Scull57e12682015-09-16 11:30:19 -07001768 // Legalize will likely need a movw/movt combination, but if the top bits are
1769 // all 0 from negating the offset and subtracting, we could use that instead.
John Porto866b6b12015-12-03 09:45:31 -08001770 const bool ShouldSub = Offset != 0 && (-Offset & 0xFFFF0000) == 0;
1771 Variable *ScratchReg = Target->makeReg(IceType_i32, ScratchRegNum);
1772 if (ShouldSub) {
1773 Operand *OffsetVal =
1774 Target->legalize(Target->Ctx->getConstantInt32(-Offset),
1775 Legal_Reg | Legal_Flex, ScratchRegNum);
1776 Target->_sub(ScratchReg, Base, OffsetVal);
1777 } else {
1778 Operand *OffsetVal =
1779 Target->legalize(Target->Ctx->getConstantInt32(Offset),
1780 Legal_Reg | Legal_Flex, ScratchRegNum);
1781 Target->_add(ScratchReg, Base, OffsetVal);
1782 }
1783
1784 if (ScratchRegNum == Target->getReservedTmpReg()) {
1785 const bool BaseIsStackOrFramePtr =
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001786 Base->getRegNum() == Target->getFrameOrStackReg();
John Porto866b6b12015-12-03 09:45:31 -08001787 // There is currently no code path that would trigger this assertion, so we
1788 // leave this assertion here in case it is ever violated. This is not a
1789 // fatal error (thus the use of assert() and not llvm::report_fatal_error)
1790 // as the program compiled by subzero will still work correctly.
1791 assert(BaseIsStackOrFramePtr);
1792 // Side-effect: updates TempBase to reflect the new Temporary.
1793 if (BaseIsStackOrFramePtr) {
1794 TempBaseReg = ScratchReg;
1795 TempBaseOffset = Offset;
1796 } else {
1797 TempBaseReg = nullptr;
1798 TempBaseOffset = 0;
1799 }
1800 }
1801
John Portof5f02f72015-11-09 14:52:40 -08001802 return ScratchReg;
1803}
1804
John Porto866b6b12015-12-03 09:45:31 -08001805OperandARM32Mem *TargetARM32::PostLoweringLegalizer::createMemOperand(
1806 Type Ty, Variable *Base, int32_t Offset, bool AllowOffsets) {
1807 assert(!Base->isRematerializable());
John Porto52b51572015-12-05 14:16:25 -08001808 if (Offset == 0 || (AllowOffsets && Target->isLegalMemOffset(Ty, Offset))) {
John Porto3f6b47d2015-11-19 05:42:59 -08001809 return OperandARM32Mem::create(
John Porto866b6b12015-12-03 09:45:31 -08001810 Target->Func, Ty, Base,
1811 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(Offset)),
John Porto3f6b47d2015-11-19 05:42:59 -08001812 OperandARM32Mem::Offset);
1813 }
1814
John Porto866b6b12015-12-03 09:45:31 -08001815 if (!AllowOffsets || TempBaseReg == nullptr) {
1816 newBaseRegister(Base, Offset, Target->getReservedTmpReg());
John Portof5f02f72015-11-09 14:52:40 -08001817 }
1818
John Porto866b6b12015-12-03 09:45:31 -08001819 int32_t OffsetDiff = Offset - TempBaseOffset;
1820 assert(AllowOffsets || OffsetDiff == 0);
1821
1822 if (!Target->isLegalMemOffset(Ty, OffsetDiff)) {
1823 newBaseRegister(Base, Offset, Target->getReservedTmpReg());
John Portof5f02f72015-11-09 14:52:40 -08001824 OffsetDiff = 0;
1825 }
1826
John Porto866b6b12015-12-03 09:45:31 -08001827 assert(!TempBaseReg->isRematerializable());
John Porto3f6b47d2015-11-19 05:42:59 -08001828 return OperandARM32Mem::create(
John Porto866b6b12015-12-03 09:45:31 -08001829 Target->Func, Ty, TempBaseReg,
1830 llvm::cast<ConstantInteger32>(Target->Ctx->getConstantInt32(OffsetDiff)),
John Porto3f6b47d2015-11-19 05:42:59 -08001831 OperandARM32Mem::Offset);
John Portof5f02f72015-11-09 14:52:40 -08001832}
1833
John Porto866b6b12015-12-03 09:45:31 -08001834void TargetARM32::PostLoweringLegalizer::resetTempBaseIfClobberedBy(
1835 const Inst *Instr) {
1836 bool ClobbersTempBase = false;
1837 if (TempBaseReg != nullptr) {
1838 Variable *Dest = Instr->getDest();
1839 if (llvm::isa<InstARM32Call>(Instr)) {
1840 // The following assertion is an invariant, so we remove it from the if
1841 // test. If the invariant is ever broken/invalidated/changed, remember
1842 // to add it back to the if condition.
1843 assert(TempBaseReg->getRegNum() == Target->getReservedTmpReg());
1844 // The linker may need to clobber IP if the call is too far from PC. Thus,
1845 // we assume IP will be overwritten.
1846 ClobbersTempBase = true;
1847 } else if (Dest != nullptr &&
1848 Dest->getRegNum() == TempBaseReg->getRegNum()) {
1849 // Register redefinition.
1850 ClobbersTempBase = true;
1851 }
1852 }
1853
1854 if (ClobbersTempBase) {
1855 TempBaseReg = nullptr;
1856 TempBaseOffset = 0;
1857 }
1858}
1859
1860void TargetARM32::PostLoweringLegalizer::legalizeMov(InstARM32Mov *MovInstr) {
John Portof5f02f72015-11-09 14:52:40 -08001861 Variable *Dest = MovInstr->getDest();
1862 assert(Dest != nullptr);
1863 Type DestTy = Dest->getType();
1864 assert(DestTy != IceType_i64);
1865
1866 Operand *Src = MovInstr->getSrc(0);
1867 Type SrcTy = Src->getType();
John Porto3f6b47d2015-11-19 05:42:59 -08001868 (void)SrcTy;
John Portof5f02f72015-11-09 14:52:40 -08001869 assert(SrcTy != IceType_i64);
1870
1871 if (MovInstr->isMultiDest() || MovInstr->isMultiSource())
1872 return;
1873
1874 bool Legalized = false;
1875 if (!Dest->hasReg()) {
John Porto614140e2015-11-23 11:43:13 -08001876 auto *SrcR = llvm::cast<Variable>(Src);
John Porto3f6b47d2015-11-19 05:42:59 -08001877 assert(SrcR->hasReg());
John Porto614140e2015-11-23 11:43:13 -08001878 assert(!SrcR->isRematerializable());
John Portof5f02f72015-11-09 14:52:40 -08001879 const int32_t Offset = Dest->getStackOffset();
John Porto3f6b47d2015-11-19 05:42:59 -08001880 // This is a _mov(Mem(), Variable), i.e., a store.
John Porto52b51572015-12-05 14:16:25 -08001881 TargetARM32::Sandboxer(Target)
1882 .str(SrcR, createMemOperand(DestTy, StackOrFrameReg, Offset),
1883 MovInstr->getPredicate());
John Porto3f6b47d2015-11-19 05:42:59 -08001884 // _str() does not have a Dest, so we add a fake-def(Dest).
John Porto1d937a82015-12-17 06:19:34 -08001885 Target->Context.insert<InstFakeDef>(Dest);
John Porto3f6b47d2015-11-19 05:42:59 -08001886 Legalized = true;
John Portof5f02f72015-11-09 14:52:40 -08001887 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) {
John Porto614140e2015-11-23 11:43:13 -08001888 if (Var->isRematerializable()) {
John Porto866b6b12015-12-03 09:45:31 -08001889 // This is equivalent to an x86 _lea(RematOffset(%esp/%ebp), Variable).
1890
1891 // ExtraOffset is only needed for frame-pointer based frames as we have
1892 // to account for spill storage.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001893 const int32_t ExtraOffset = (Var->getRegNum() == Target->getFrameReg())
1894 ? Target->getFrameFixedAllocaOffset()
1895 : 0;
John Porto614140e2015-11-23 11:43:13 -08001896
1897 const int32_t Offset = Var->getStackOffset() + ExtraOffset;
John Porto866b6b12015-12-03 09:45:31 -08001898 Variable *Base = Target->getPhysicalRegister(Var->getRegNum());
1899 Variable *T = newBaseRegister(Base, Offset, Dest->getRegNum());
1900 Target->_mov(Dest, T);
John Porto3f6b47d2015-11-19 05:42:59 -08001901 Legalized = true;
John Porto614140e2015-11-23 11:43:13 -08001902 } else {
1903 if (!Var->hasReg()) {
John Porto866b6b12015-12-03 09:45:31 -08001904 // This is a _mov(Variable, Mem()), i.e., a load.
John Porto614140e2015-11-23 11:43:13 -08001905 const int32_t Offset = Var->getStackOffset();
John Porto52b51572015-12-05 14:16:25 -08001906 TargetARM32::Sandboxer(Target)
1907 .ldr(Dest, createMemOperand(DestTy, StackOrFrameReg, Offset),
1908 MovInstr->getPredicate());
John Porto614140e2015-11-23 11:43:13 -08001909 Legalized = true;
1910 }
John Portof5f02f72015-11-09 14:52:40 -08001911 }
1912 }
1913
1914 if (Legalized) {
John Porto7b3d9cb2015-11-11 14:26:57 -08001915 if (MovInstr->isDestRedefined()) {
John Porto866b6b12015-12-03 09:45:31 -08001916 Target->_set_dest_redefined();
John Porto7b3d9cb2015-11-11 14:26:57 -08001917 }
John Portof5f02f72015-11-09 14:52:40 -08001918 MovInstr->setDeleted();
1919 }
Jan Voung28068ad2015-07-31 12:58:46 -07001920}
1921
John Porto866b6b12015-12-03 09:45:31 -08001922// ARM32 address modes:
1923// ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12],
1924// [reg +/- reg << shamt5]
1925// ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8]
1926// ld/st vectors : [reg]
1927//
1928// For now, we don't handle address modes with Relocatables.
1929namespace {
1930// MemTraits contains per-type valid address mode information.
John Porto15e77d42016-04-13 12:57:14 -07001931#define X(tag, elementty, int_width, fp_width, uvec_width, svec_width, sbits, \
1932 ubits, rraddr, shaddr) \
John Porto866b6b12015-12-03 09:45:31 -08001933 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag);
1934ICETYPEARM32_TABLE
1935#undef X
1936
1937static const struct {
1938 int32_t ValidImmMask;
1939 bool CanHaveImm;
1940 bool CanHaveIndex;
1941 bool CanHaveShiftedIndex;
1942} MemTraits[] = {
John Porto15e77d42016-04-13 12:57:14 -07001943#define X(tag, elementty, int_width, fp_width, uvec_width, svec_width, sbits, \
1944 ubits, rraddr, shaddr) \
John Porto866b6b12015-12-03 09:45:31 -08001945 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \
1946 ,
1947 ICETYPEARM32_TABLE
1948#undef X
1949};
1950static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits);
1951} // end of anonymous namespace
1952
1953OperandARM32Mem *
1954TargetARM32::PostLoweringLegalizer::legalizeMemOperand(OperandARM32Mem *Mem,
1955 bool AllowOffsets) {
1956 assert(!Mem->isRegReg() || !Mem->getIndex()->isRematerializable());
1957 assert(
1958 Mem->isRegReg() ||
1959 Target->isLegalMemOffset(Mem->getType(), Mem->getOffset()->getValue()));
1960
1961 bool Legalized = false;
1962 Variable *Base = Mem->getBase();
1963 int32_t Offset = Mem->isRegReg() ? 0 : Mem->getOffset()->getValue();
1964 if (Base->isRematerializable()) {
Jim Stichnoth8aa39662016-02-10 11:20:30 -08001965 const int32_t ExtraOffset = (Base->getRegNum() == Target->getFrameReg())
1966 ? Target->getFrameFixedAllocaOffset()
1967 : 0;
John Porto866b6b12015-12-03 09:45:31 -08001968 Offset += Base->getStackOffset() + ExtraOffset;
1969 Base = Target->getPhysicalRegister(Base->getRegNum());
1970 assert(!Base->isRematerializable());
1971 Legalized = true;
1972 }
1973
John Porto52b51572015-12-05 14:16:25 -08001974 if (!Legalized && !Target->NeedSandboxing) {
John Porto866b6b12015-12-03 09:45:31 -08001975 return nullptr;
1976 }
1977
1978 if (!Mem->isRegReg()) {
1979 return createMemOperand(Mem->getType(), Base, Offset, AllowOffsets);
1980 }
1981
John Porto52b51572015-12-05 14:16:25 -08001982 if (Target->NeedSandboxing) {
1983 llvm::report_fatal_error("Reg-Reg address mode is not allowed.");
1984 }
1985
John Porto866b6b12015-12-03 09:45:31 -08001986 assert(MemTraits[Mem->getType()].CanHaveIndex);
1987
1988 if (Offset != 0) {
1989 if (TempBaseReg == nullptr) {
1990 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
1991 } else {
1992 uint32_t Imm8, Rotate;
1993 const int32_t OffsetDiff = Offset - TempBaseOffset;
1994 if (OffsetDiff == 0) {
1995 Base = TempBaseReg;
1996 } else if (OperandARM32FlexImm::canHoldImm(OffsetDiff, &Rotate, &Imm8)) {
1997 auto *OffsetDiffF = OperandARM32FlexImm::create(
1998 Target->Func, IceType_i32, Imm8, Rotate);
1999 Target->_add(TempBaseReg, TempBaseReg, OffsetDiffF);
2000 TempBaseOffset += OffsetDiff;
2001 Base = TempBaseReg;
2002 } else if (OperandARM32FlexImm::canHoldImm(-OffsetDiff, &Rotate, &Imm8)) {
2003 auto *OffsetDiffF = OperandARM32FlexImm::create(
2004 Target->Func, IceType_i32, Imm8, Rotate);
2005 Target->_sub(TempBaseReg, TempBaseReg, OffsetDiffF);
2006 TempBaseOffset += OffsetDiff;
2007 Base = TempBaseReg;
2008 } else {
2009 Base = newBaseRegister(Base, Offset, Target->getReservedTmpReg());
2010 }
2011 }
2012 }
2013
2014 return OperandARM32Mem::create(Target->Func, Mem->getType(), Base,
2015 Mem->getIndex(), Mem->getShiftOp(),
2016 Mem->getShiftAmt(), Mem->getAddrMode());
2017}
2018
2019void TargetARM32::postLowerLegalization() {
Jan Voung28068ad2015-07-31 12:58:46 -07002020 // If a stack variable's frame offset doesn't fit, convert from:
2021 // ldr X, OFF[SP]
2022 // to:
2023 // movw/movt TMP, OFF_PART
2024 // add TMP, TMP, SP
2025 // ldr X, OFF_MORE[TMP]
2026 //
2027 // This is safe because we have reserved TMP, and add for ARM does not
2028 // clobber the flags register.
John Porto866b6b12015-12-03 09:45:31 -08002029 Func->dump("Before postLowerLegalization");
Jan Voung28068ad2015-07-31 12:58:46 -07002030 assert(hasComputedFrame());
Andrew Scull57e12682015-09-16 11:30:19 -07002031 // Do a fairly naive greedy clustering for now. Pick the first stack slot
Jan Voung28068ad2015-07-31 12:58:46 -07002032 // that's out of bounds and make a new base reg using the architecture's temp
Andrew Scull57e12682015-09-16 11:30:19 -07002033 // register. If that works for the next slot, then great. Otherwise, create a
2034 // new base register, clobbering the previous base register. Never share a
2035 // base reg across different basic blocks. This isn't ideal if local and
Jan Voung28068ad2015-07-31 12:58:46 -07002036 // multi-block variables are far apart and their references are interspersed.
Andrew Scull57e12682015-09-16 11:30:19 -07002037 // It may help to be more coordinated about assign stack slot numbers and may
2038 // help to assign smaller offsets to higher-weight variables so that they
2039 // don't depend on this legalization.
Jan Voung28068ad2015-07-31 12:58:46 -07002040 for (CfgNode *Node : Func->getNodes()) {
2041 Context.init(Node);
John Porto866b6b12015-12-03 09:45:31 -08002042 // One legalizer per basic block, otherwise we would share the Temporary
2043 // Base Register between basic blocks.
2044 PostLoweringLegalizer Legalizer(this);
Jan Voung28068ad2015-07-31 12:58:46 -07002045 while (!Context.atEnd()) {
2046 PostIncrLoweringContext PostIncrement(Context);
Jim Stichnothf5fdd232016-05-09 12:24:36 -07002047 Inst *CurInstr = iteratorToInst(Context.getCur());
John Portof5f02f72015-11-09 14:52:40 -08002048
John Porto866b6b12015-12-03 09:45:31 -08002049 // Check if the previous TempBaseReg is clobbered, and reset if needed.
2050 Legalizer.resetTempBaseIfClobberedBy(CurInstr);
John Portof5f02f72015-11-09 14:52:40 -08002051
John Portoba6a67c2015-09-25 15:19:45 -07002052 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) {
John Porto866b6b12015-12-03 09:45:31 -08002053 Legalizer.legalizeMov(MovInstr);
2054 } else if (auto *LdrInstr = llvm::dyn_cast<InstARM32Ldr>(CurInstr)) {
2055 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
2056 llvm::cast<OperandARM32Mem>(LdrInstr->getSrc(0)))) {
John Porto52b51572015-12-05 14:16:25 -08002057 Sandboxer(this)
2058 .ldr(CurInstr->getDest(), LegalMem, LdrInstr->getPredicate());
John Porto866b6b12015-12-03 09:45:31 -08002059 CurInstr->setDeleted();
2060 }
2061 } else if (auto *LdrexInstr = llvm::dyn_cast<InstARM32Ldrex>(CurInstr)) {
2062 constexpr bool DisallowOffsetsBecauseLdrex = false;
2063 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
2064 llvm::cast<OperandARM32Mem>(LdrexInstr->getSrc(0)),
2065 DisallowOffsetsBecauseLdrex)) {
John Porto52b51572015-12-05 14:16:25 -08002066 Sandboxer(this)
2067 .ldrex(CurInstr->getDest(), LegalMem, LdrexInstr->getPredicate());
John Porto866b6b12015-12-03 09:45:31 -08002068 CurInstr->setDeleted();
2069 }
2070 } else if (auto *StrInstr = llvm::dyn_cast<InstARM32Str>(CurInstr)) {
2071 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
2072 llvm::cast<OperandARM32Mem>(StrInstr->getSrc(1)))) {
John Porto52b51572015-12-05 14:16:25 -08002073 Sandboxer(this).str(llvm::cast<Variable>(CurInstr->getSrc(0)),
2074 LegalMem, StrInstr->getPredicate());
John Porto866b6b12015-12-03 09:45:31 -08002075 CurInstr->setDeleted();
2076 }
2077 } else if (auto *StrexInstr = llvm::dyn_cast<InstARM32Strex>(CurInstr)) {
2078 constexpr bool DisallowOffsetsBecauseStrex = false;
2079 if (OperandARM32Mem *LegalMem = Legalizer.legalizeMemOperand(
2080 llvm::cast<OperandARM32Mem>(StrexInstr->getSrc(1)),
2081 DisallowOffsetsBecauseStrex)) {
John Porto52b51572015-12-05 14:16:25 -08002082 Sandboxer(this).strex(CurInstr->getDest(),
2083 llvm::cast<Variable>(CurInstr->getSrc(0)),
2084 LegalMem, StrexInstr->getPredicate());
John Porto866b6b12015-12-03 09:45:31 -08002085 CurInstr->setDeleted();
2086 }
Jan Voung28068ad2015-07-31 12:58:46 -07002087 }
John Porto866b6b12015-12-03 09:45:31 -08002088
2089 // Sanity-check: the Legalizer will either have no Temp, or it will be
2090 // bound to IP.
2091 Legalizer.assertNoTempOrAssignedToIP();
Jan Voung28068ad2015-07-31 12:58:46 -07002092 }
2093 }
2094}
2095
Jan Voungb3401d22015-05-18 09:38:21 -07002096Operand *TargetARM32::loOperand(Operand *Operand) {
2097 assert(Operand->getType() == IceType_i64);
2098 if (Operand->getType() != IceType_i64)
2099 return Operand;
Andrew Scull6d47bcd2015-09-17 17:10:05 -07002100 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2101 return Var64On32->getLo();
2102 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand))
Jan Voungb3401d22015-05-18 09:38:21 -07002103 return Ctx->getConstantInt32(static_cast<uint32_t>(Const->getValue()));
Jan Voungfbdd2442015-07-15 12:36:20 -07002104 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
Jan Voungb3401d22015-05-18 09:38:21 -07002105 // Conservatively disallow memory operands with side-effects (pre/post
2106 // increment) in case of duplication.
2107 assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
2108 Mem->getAddrMode() == OperandARM32Mem::NegOffset);
2109 if (Mem->isRegReg()) {
John Porto614140e2015-11-23 11:43:13 -08002110 Variable *IndexR = legalizeToReg(Mem->getIndex());
John Porto866b6b12015-12-03 09:45:31 -08002111 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(), IndexR,
John Porto614140e2015-11-23 11:43:13 -08002112 Mem->getShiftOp(), Mem->getShiftAmt(),
2113 Mem->getAddrMode());
Jan Voungb3401d22015-05-18 09:38:21 -07002114 } else {
John Porto866b6b12015-12-03 09:45:31 -08002115 return OperandARM32Mem::create(Func, IceType_i32, Mem->getBase(),
2116 Mem->getOffset(), Mem->getAddrMode());
Jan Voungb3401d22015-05-18 09:38:21 -07002117 }
2118 }
John Portoc39ec102015-12-01 13:00:43 -08002119 llvm::report_fatal_error("Unsupported operand type");
Jan Voungb3401d22015-05-18 09:38:21 -07002120 return nullptr;
2121}
2122
2123Operand *TargetARM32::hiOperand(Operand *Operand) {
2124 assert(Operand->getType() == IceType_i64);
2125 if (Operand->getType() != IceType_i64)
2126 return Operand;
Andrew Scull6d47bcd2015-09-17 17:10:05 -07002127 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand))
2128 return Var64On32->getHi();
Jan Voungfbdd2442015-07-15 12:36:20 -07002129 if (auto *Const = llvm::dyn_cast<ConstantInteger64>(Operand)) {
Jan Voungb3401d22015-05-18 09:38:21 -07002130 return Ctx->getConstantInt32(
2131 static_cast<uint32_t>(Const->getValue() >> 32));
2132 }
Jan Voungfbdd2442015-07-15 12:36:20 -07002133 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand)) {
Andrew Scull57e12682015-09-16 11:30:19 -07002134 // Conservatively disallow memory operands with side-effects in case of
2135 // duplication.
Jan Voungb3401d22015-05-18 09:38:21 -07002136 assert(Mem->getAddrMode() == OperandARM32Mem::Offset ||
2137 Mem->getAddrMode() == OperandARM32Mem::NegOffset);
2138 const Type SplitType = IceType_i32;
2139 if (Mem->isRegReg()) {
2140 // We have to make a temp variable T, and add 4 to either Base or Index.
Andrew Scull57e12682015-09-16 11:30:19 -07002141 // The Index may be shifted, so adding 4 can mean something else. Thus,
2142 // prefer T := Base + 4, and use T as the new Base.
Jan Voungb3401d22015-05-18 09:38:21 -07002143 Variable *Base = Mem->getBase();
2144 Constant *Four = Ctx->getConstantInt32(4);
2145 Variable *NewBase = Func->makeVariable(Base->getType());
2146 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase,
2147 Base, Four));
John Porto614140e2015-11-23 11:43:13 -08002148 Variable *BaseR = legalizeToReg(NewBase);
2149 Variable *IndexR = legalizeToReg(Mem->getIndex());
2150 return OperandARM32Mem::create(Func, SplitType, BaseR, IndexR,
Jan Voungb3401d22015-05-18 09:38:21 -07002151 Mem->getShiftOp(), Mem->getShiftAmt(),
2152 Mem->getAddrMode());
2153 } else {
2154 Variable *Base = Mem->getBase();
2155 ConstantInteger32 *Offset = Mem->getOffset();
2156 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4));
2157 int32_t NextOffsetVal = Offset->getValue() + 4;
John Portof5f02f72015-11-09 14:52:40 -08002158 constexpr bool ZeroExt = false;
2159 if (!OperandARM32Mem::canHoldOffset(SplitType, ZeroExt, NextOffsetVal)) {
Jan Voungb3401d22015-05-18 09:38:21 -07002160 // We have to make a temp variable and add 4 to either Base or Offset.
2161 // If we add 4 to Offset, this will convert a non-RegReg addressing
2162 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows
Andrew Scull57e12682015-09-16 11:30:19 -07002163 // RegReg addressing modes, prefer adding to base and replacing
2164 // instead. Thus we leave the old offset alone.
John Porto614140e2015-11-23 11:43:13 -08002165 Constant *_4 = Ctx->getConstantInt32(4);
Jan Voungb3401d22015-05-18 09:38:21 -07002166 Variable *NewBase = Func->makeVariable(Base->getType());
2167 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add,
John Porto614140e2015-11-23 11:43:13 -08002168 NewBase, Base, _4));
Jan Voungb3401d22015-05-18 09:38:21 -07002169 Base = NewBase;
2170 } else {
2171 Offset =
2172 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(NextOffsetVal));
2173 }
John Porto614140e2015-11-23 11:43:13 -08002174 Variable *BaseR = legalizeToReg(Base);
2175 return OperandARM32Mem::create(Func, SplitType, BaseR, Offset,
Jan Voungb3401d22015-05-18 09:38:21 -07002176 Mem->getAddrMode());
2177 }
2178 }
John Portoc39ec102015-12-01 13:00:43 -08002179 llvm::report_fatal_error("Unsupported operand type");
Jan Voungb3401d22015-05-18 09:38:21 -07002180 return nullptr;
2181}
2182
John Portoe82b5602016-02-24 15:58:55 -08002183SmallBitVector TargetARM32::getRegisterSet(RegSetMask Include,
2184 RegSetMask Exclude) const {
2185 SmallBitVector Registers(RegARM32::Reg_NUM);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002186
Jim Stichnoth8aa39662016-02-10 11:20:30 -08002187 for (uint32_t i = 0; i < RegARM32::Reg_NUM; ++i) {
Karl Schimpf57ec7df2016-01-15 08:11:00 -08002188 const auto &Entry = RegARM32::RegTable[i];
John Porto149999e2016-01-04 13:45:26 -08002189 if (Entry.Scratch && (Include & RegSet_CallerSave))
2190 Registers[i] = true;
2191 if (Entry.Preserved && (Include & RegSet_CalleeSave))
2192 Registers[i] = true;
2193 if (Entry.StackPtr && (Include & RegSet_StackPointer))
2194 Registers[i] = true;
2195 if (Entry.FramePtr && (Include & RegSet_FramePointer))
2196 Registers[i] = true;
2197 if (Entry.Scratch && (Exclude & RegSet_CallerSave))
2198 Registers[i] = false;
2199 if (Entry.Preserved && (Exclude & RegSet_CalleeSave))
2200 Registers[i] = false;
2201 if (Entry.StackPtr && (Exclude & RegSet_StackPointer))
2202 Registers[i] = false;
2203 if (Entry.FramePtr && (Exclude & RegSet_FramePointer))
2204 Registers[i] = false;
2205 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07002206
2207 return Registers;
2208}
2209
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002210void TargetARM32::lowerAlloca(const InstAlloca *Instr) {
Andrew Scull57e12682015-09-16 11:30:19 -07002211 // Conservatively require the stack to be aligned. Some stack adjustment
2212 // operations implemented below assume that the stack is aligned before the
2213 // alloca. All the alloca code ensures that the stack alignment is preserved
2214 // after the alloca. The stack alignment restriction can be relaxed in some
2215 // cases.
Jan Voungb36ad9b2015-04-21 17:01:49 -07002216 NeedsStackAlignment = true;
Jan Voung55500db2015-05-26 14:25:40 -07002217
Jan Voung55500db2015-05-26 14:25:40 -07002218 // For default align=0, set it to the real value 1, to avoid any
2219 // bit-manipulation problems below.
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002220 const uint32_t AlignmentParam = std::max(1u, Instr->getAlignInBytes());
Jan Voung55500db2015-05-26 14:25:40 -07002221
2222 // LLVM enforces power of 2 alignment.
2223 assert(llvm::isPowerOf2_32(AlignmentParam));
2224 assert(llvm::isPowerOf2_32(ARM32_STACK_ALIGNMENT_BYTES));
2225
John Porto614140e2015-11-23 11:43:13 -08002226 const uint32_t Alignment =
2227 std::max(AlignmentParam, ARM32_STACK_ALIGNMENT_BYTES);
2228 const bool OverAligned = Alignment > ARM32_STACK_ALIGNMENT_BYTES;
Jim Stichnoth386b52e2016-08-05 15:18:41 -07002229 const bool OptM1 = Func->getOptLevel() == Opt_m1;
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002230 const bool AllocaWithKnownOffset = Instr->getKnownFrameOffset();
John Porto614140e2015-11-23 11:43:13 -08002231 const bool UseFramePointer =
2232 hasFramePointer() || OverAligned || !AllocaWithKnownOffset || OptM1;
2233
2234 if (UseFramePointer)
2235 setHasFramePointer();
2236
2237 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
2238 if (OverAligned) {
John Porto52b51572015-12-05 14:16:25 -08002239 Sandboxer(this).align_sp(Alignment);
Jan Voung55500db2015-05-26 14:25:40 -07002240 }
John Porto614140e2015-11-23 11:43:13 -08002241
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002242 Variable *Dest = Instr->getDest();
2243 Operand *TotalSize = Instr->getSizeInBytes();
John Porto614140e2015-11-23 11:43:13 -08002244
Jan Voung55500db2015-05-26 14:25:40 -07002245 if (const auto *ConstantTotalSize =
2246 llvm::dyn_cast<ConstantInteger32>(TotalSize)) {
John Porto614140e2015-11-23 11:43:13 -08002247 const uint32_t Value =
2248 Utils::applyAlignment(ConstantTotalSize->getValue(), Alignment);
2249 // Constant size alloca.
2250 if (!UseFramePointer) {
2251 // If we don't need a Frame Pointer, this alloca has a known offset to the
2252 // stack pointer. We don't need adjust the stack pointer, nor assign any
2253 // value to Dest, as Dest is rematerializable.
2254 assert(Dest->isRematerializable());
2255 FixedAllocaSizeBytes += Value;
John Porto1d937a82015-12-17 06:19:34 -08002256 Context.insert<InstFakeDef>(Dest);
John Porto614140e2015-11-23 11:43:13 -08002257 return;
2258 }
2259
2260 // If a frame pointer is required, then we need to store the alloca'd result
2261 // in Dest.
2262 Operand *SubAmountRF =
2263 legalize(Ctx->getConstantInt32(Value), Legal_Reg | Legal_Flex);
John Porto52b51572015-12-05 14:16:25 -08002264 Sandboxer(this).sub_sp(SubAmountRF);
Jan Voung55500db2015-05-26 14:25:40 -07002265 } else {
Andrew Scull57e12682015-09-16 11:30:19 -07002266 // Non-constant sizes need to be adjusted to the next highest multiple of
2267 // the required alignment at runtime.
Jan Voungfbdd2442015-07-15 12:36:20 -07002268 TotalSize = legalize(TotalSize, Legal_Reg | Legal_Flex);
Jan Voung55500db2015-05-26 14:25:40 -07002269 Variable *T = makeReg(IceType_i32);
2270 _mov(T, TotalSize);
2271 Operand *AddAmount = legalize(Ctx->getConstantInt32(Alignment - 1));
2272 _add(T, T, AddAmount);
2273 alignRegisterPow2(T, Alignment);
John Porto52b51572015-12-05 14:16:25 -08002274 Sandboxer(this).sub_sp(T);
Jan Voung55500db2015-05-26 14:25:40 -07002275 }
John Porto614140e2015-11-23 11:43:13 -08002276
2277 // Adds back a few bytes to SP to account for the out args area.
John Portof4198542015-11-20 14:17:23 -08002278 Variable *T = SP;
2279 if (MaxOutArgsSizeBytes != 0) {
2280 T = makeReg(getPointerType());
2281 Operand *OutArgsSizeRF = legalize(
2282 Ctx->getConstantInt32(MaxOutArgsSizeBytes), Legal_Reg | Legal_Flex);
2283 _add(T, SP, OutArgsSizeRF);
2284 }
John Porto614140e2015-11-23 11:43:13 -08002285
John Portof4198542015-11-20 14:17:23 -08002286 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07002287}
2288
Jan Voung6ec369e2015-06-30 11:03:15 -07002289void TargetARM32::div0Check(Type Ty, Operand *SrcLo, Operand *SrcHi) {
2290 if (isGuaranteedNonzeroInt(SrcLo) || isGuaranteedNonzeroInt(SrcHi))
2291 return;
Andrew Scull97f460d2015-07-21 10:07:42 -07002292 Variable *SrcLoReg = legalizeToReg(SrcLo);
Jan Voung6ec369e2015-06-30 11:03:15 -07002293 switch (Ty) {
2294 default:
Eric Holkcfc25532016-02-09 17:47:58 -08002295 llvm_unreachable(
Jim Stichnoth467ffe52016-03-29 15:01:06 -07002296 ("Unexpected type in div0Check: " + typeStdString(Ty)).c_str());
John Portoccea7932015-11-17 04:58:36 -08002297 case IceType_i8:
Jan Voung6ec369e2015-06-30 11:03:15 -07002298 case IceType_i16: {
John Porto2758bb02015-11-17 14:31:25 -08002299 Operand *ShAmtImm = shAmtImm(32 - getScalarIntBitWidth(Ty));
John Portoccea7932015-11-17 04:58:36 -08002300 Variable *T = makeReg(IceType_i32);
John Porto2758bb02015-11-17 14:31:25 -08002301 _lsls(T, SrcLoReg, ShAmtImm);
John Porto1d937a82015-12-17 06:19:34 -08002302 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08002303 } break;
Jan Voung6ec369e2015-06-30 11:03:15 -07002304 case IceType_i32: {
2305 _tst(SrcLoReg, SrcLoReg);
2306 break;
2307 }
2308 case IceType_i64: {
John Portoccea7932015-11-17 04:58:36 -08002309 Variable *T = makeReg(IceType_i32);
2310 _orrs(T, SrcLoReg, legalize(SrcHi, Legal_Reg | Legal_Flex));
2311 // T isn't going to be used, but we need the side-effect of setting flags
2312 // from this operation.
John Porto1d937a82015-12-17 06:19:34 -08002313 Context.insert<InstFakeUse>(T);
Jan Voung6ec369e2015-06-30 11:03:15 -07002314 }
2315 }
Jim Stichnoth54f3d512015-12-11 09:53:00 -08002316 auto *Label = InstARM32Label::create(Func, this);
Jan Voung6ec369e2015-06-30 11:03:15 -07002317 _br(Label, CondARM32::NE);
2318 _trap();
2319 Context.insert(Label);
2320}
2321
2322void TargetARM32::lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R,
2323 Operand *Src1, ExtInstr ExtFunc,
John Portoc39ec102015-12-01 13:00:43 -08002324 DivInstr DivFunc, bool IsRemainder) {
Jan Voung6ec369e2015-06-30 11:03:15 -07002325 div0Check(Dest->getType(), Src1, nullptr);
Andrew Scull97f460d2015-07-21 10:07:42 -07002326 Variable *Src1R = legalizeToReg(Src1);
Jan Voung6ec369e2015-06-30 11:03:15 -07002327 Variable *T0R = Src0R;
2328 Variable *T1R = Src1R;
2329 if (Dest->getType() != IceType_i32) {
2330 T0R = makeReg(IceType_i32);
2331 (this->*ExtFunc)(T0R, Src0R, CondARM32::AL);
2332 T1R = makeReg(IceType_i32);
2333 (this->*ExtFunc)(T1R, Src1R, CondARM32::AL);
2334 }
2335 if (hasCPUFeature(TargetARM32Features::HWDivArm)) {
2336 (this->*DivFunc)(T, T0R, T1R, CondARM32::AL);
2337 if (IsRemainder) {
2338 Variable *T2 = makeReg(IceType_i32);
2339 _mls(T2, T, T1R, T0R);
2340 T = T2;
2341 }
2342 _mov(Dest, T);
2343 } else {
John Portoc39ec102015-12-01 13:00:43 -08002344 llvm::report_fatal_error("div should have already been turned into a call");
Jan Voung6ec369e2015-06-30 11:03:15 -07002345 }
Jan Voung6ec369e2015-06-30 11:03:15 -07002346}
2347
John Porto7b3d9cb2015-11-11 14:26:57 -08002348TargetARM32::SafeBoolChain
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002349TargetARM32::lowerInt1Arithmetic(const InstArithmetic *Instr) {
2350 Variable *Dest = Instr->getDest();
John Porto7b3d9cb2015-11-11 14:26:57 -08002351 assert(Dest->getType() == IceType_i1);
2352
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002353 // So folding didn't work for Instr. Not a problem: We just need to
John Porto7b3d9cb2015-11-11 14:26:57 -08002354 // materialize the Sources, and perform the operation. We create regular
2355 // Variables (and not infinite-weight ones) because this call might recurse a
2356 // lot, and we might end up with tons of infinite weight temporaries.
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002357 assert(Instr->getSrcSize() == 2);
John Porto7b3d9cb2015-11-11 14:26:57 -08002358 Variable *Src0 = Func->makeVariable(IceType_i1);
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002359 SafeBoolChain Src0Safe = lowerInt1(Src0, Instr->getSrc(0));
John Porto7b3d9cb2015-11-11 14:26:57 -08002360
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002361 Operand *Src1 = Instr->getSrc(1);
John Porto7b3d9cb2015-11-11 14:26:57 -08002362 SafeBoolChain Src1Safe = SBC_Yes;
2363
2364 if (!llvm::isa<Constant>(Src1)) {
2365 Variable *Src1V = Func->makeVariable(IceType_i1);
2366 Src1Safe = lowerInt1(Src1V, Src1);
2367 Src1 = Src1V;
2368 }
2369
2370 Variable *T = makeReg(IceType_i1);
2371 Src0 = legalizeToReg(Src0);
2372 Operand *Src1RF = legalize(Src1, Legal_Reg | Legal_Flex);
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08002373 switch (Instr->getOp()) {
John Porto7b3d9cb2015-11-11 14:26:57 -08002374 default:
2375 // If this Unreachable is ever executed, add the offending operation to
2376 // the list of valid consumers.
2377 llvm::report_fatal_error("Unhandled i1 Op");
2378 case InstArithmetic::And:
2379 _and(T, Src0, Src1RF);
2380 break;
2381 case InstArithmetic::Or:
2382 _orr(T, Src0, Src1RF);
2383 break;
2384 case InstArithmetic::Xor:
2385 _eor(T, Src0, Src1RF);
2386 break;
2387 }
2388 _mov(Dest, T);
2389 return Src0Safe == SBC_Yes && Src1Safe == SBC_Yes ? SBC_Yes : SBC_No;
2390}
2391
John Portoccea7932015-11-17 04:58:36 -08002392namespace {
2393// NumericOperands is used during arithmetic/icmp lowering for constant folding.
2394// It holds the two sources operands, and maintains some state as to whether one
2395// of them is a constant. If one of the operands is a constant, then it will be
2396// be stored as the operation's second source, with a bit indicating whether the
2397// operands were swapped.
2398//
2399// The class is split into a base class with operand type-independent methods,
2400// and a derived, templated class, for each type of operand we want to fold
2401// constants for:
2402//
2403// NumericOperandsBase --> NumericOperands<ConstantFloat>
2404// --> NumericOperands<ConstantDouble>
2405// --> NumericOperands<ConstantInt32>
2406//
2407// NumericOperands<ConstantInt32> also exposes helper methods for emitting
2408// inverted/negated immediates.
2409class NumericOperandsBase {
2410 NumericOperandsBase() = delete;
2411 NumericOperandsBase(const NumericOperandsBase &) = delete;
2412 NumericOperandsBase &operator=(const NumericOperandsBase &) = delete;
2413
2414public:
2415 NumericOperandsBase(Operand *S0, Operand *S1)
2416 : Src0(NonConstOperand(S0, S1)), Src1(ConstOperand(S0, S1)),
2417 Swapped(Src0 == S1 && S0 != S1) {
2418 assert(Src0 != nullptr);
2419 assert(Src1 != nullptr);
2420 assert(Src0 != Src1 || S0 == S1);
2421 }
2422
2423 bool hasConstOperand() const {
2424 return llvm::isa<Constant>(Src1) && !llvm::isa<ConstantRelocatable>(Src1);
2425 }
2426
2427 bool swappedOperands() const { return Swapped; }
2428
2429 Variable *src0R(TargetARM32 *Target) const {
2430 return legalizeToReg(Target, Src0);
2431 }
2432
2433 Variable *unswappedSrc0R(TargetARM32 *Target) const {
2434 return legalizeToReg(Target, Swapped ? Src1 : Src0);
2435 }
2436
2437 Operand *src1RF(TargetARM32 *Target) const {
2438 return legalizeToRegOrFlex(Target, Src1);
2439 }
2440
2441 Variable *unswappedSrc1R(TargetARM32 *Target) const {
2442 return legalizeToReg(Target, Swapped ? Src0 : Src1);
2443 }
2444
Nicolas Capens8d90a342017-09-27 14:33:11 -04002445 Operand *src1() const { return Src1; }
2446
John Portoccea7932015-11-17 04:58:36 -08002447protected:
2448 Operand *const Src0;
2449 Operand *const Src1;
2450 const bool Swapped;
2451
2452 static Variable *legalizeToReg(TargetARM32 *Target, Operand *Src) {
2453 return Target->legalizeToReg(Src);
2454 }
2455
2456 static Operand *legalizeToRegOrFlex(TargetARM32 *Target, Operand *Src) {
2457 return Target->legalize(Src,
2458 TargetARM32::Legal_Reg | TargetARM32::Legal_Flex);
2459 }
2460
2461private:
2462 static Operand *NonConstOperand(Operand *S0, Operand *S1) {
2463 if (!llvm::isa<Constant>(S0))
2464 return S0;
2465 if (!llvm::isa<Constant>(S1))
2466 return S1;
2467 if (llvm::isa<ConstantRelocatable>(S1) &&
2468 !llvm::isa<ConstantRelocatable>(S0))
2469 return S1;
2470 return S0;
2471 }
2472
2473 static Operand *ConstOperand(Operand *S0, Operand *S1) {
2474 if (!llvm::isa<Constant>(S0))
2475 return S1;
2476 if (!llvm::isa<Constant>(S1))
2477 return S0;
2478 if (llvm::isa<ConstantRelocatable>(S1) &&
2479 !llvm::isa<ConstantRelocatable>(S0))
2480 return S0;
2481 return S1;
2482 }
2483};
2484
2485template <typename C> class NumericOperands : public NumericOperandsBase {
2486 NumericOperands() = delete;
2487 NumericOperands(const NumericOperands &) = delete;
2488 NumericOperands &operator=(const NumericOperands &) = delete;
2489
2490public:
2491 NumericOperands(Operand *S0, Operand *S1) : NumericOperandsBase(S0, S1) {
2492 assert(!hasConstOperand() || llvm::isa<C>(this->Src1));
2493 }
2494
2495 typename C::PrimType getConstantValue() const {
2496 return llvm::cast<C>(Src1)->getValue();
2497 }
2498};
2499
2500using FloatOperands = NumericOperands<ConstantFloat>;
2501using DoubleOperands = NumericOperands<ConstantDouble>;
2502
2503class Int32Operands : public NumericOperands<ConstantInteger32> {
2504 Int32Operands() = delete;
2505 Int32Operands(const Int32Operands &) = delete;
2506 Int32Operands &operator=(const Int32Operands &) = delete;
2507
2508public:
2509 Int32Operands(Operand *S0, Operand *S1) : NumericOperands(S0, S1) {}
2510
John Porto2758bb02015-11-17 14:31:25 -08002511 Operand *unswappedSrc1RShAmtImm(TargetARM32 *Target) const {
2512 if (!swappedOperands() && hasConstOperand()) {
2513 return Target->shAmtImm(getConstantValue() & 0x1F);
2514 }
2515 return legalizeToReg(Target, Swapped ? Src0 : Src1);
2516 }
2517
Nicolas Capensfb705a62017-05-01 15:31:29 -04002518 bool isSrc1ImmediateZero() const {
2519 if (!swappedOperands() && hasConstOperand()) {
2520 return getConstantValue() == 0;
2521 }
2522 return false;
2523 }
2524
John Portoccea7932015-11-17 04:58:36 -08002525 bool immediateIsFlexEncodable() const {
2526 uint32_t Rotate, Imm8;
2527 return OperandARM32FlexImm::canHoldImm(getConstantValue(), &Rotate, &Imm8);
2528 }
2529
2530 bool negatedImmediateIsFlexEncodable() const {
2531 uint32_t Rotate, Imm8;
2532 return OperandARM32FlexImm::canHoldImm(
2533 -static_cast<int32_t>(getConstantValue()), &Rotate, &Imm8);
2534 }
2535
2536 Operand *negatedSrc1F(TargetARM32 *Target) const {
2537 return legalizeToRegOrFlex(Target,
2538 Target->getCtx()->getConstantInt32(
2539 -static_cast<int32_t>(getConstantValue())));
2540 }
2541
2542 bool invertedImmediateIsFlexEncodable() const {
2543 uint32_t Rotate, Imm8;
2544 return OperandARM32FlexImm::canHoldImm(
2545 ~static_cast<uint32_t>(getConstantValue()), &Rotate, &Imm8);
2546 }
2547
2548 Operand *invertedSrc1F(TargetARM32 *Target) const {
2549 return legalizeToRegOrFlex(Target,
2550 Target->getCtx()->getConstantInt32(
2551 ~static_cast<uint32_t>(getConstantValue())));
2552 }
2553};
2554} // end of anonymous namespace
2555
John Portoc39ec102015-12-01 13:00:43 -08002556void TargetARM32::preambleDivRem(const InstCall *Instr) {
2557 Operand *Src1 = Instr->getArg(1);
2558
2559 switch (Src1->getType()) {
2560 default:
2561 llvm::report_fatal_error("Invalid type for idiv.");
2562 case IceType_i64: {
2563 if (auto *C = llvm::dyn_cast<ConstantInteger64>(Src1)) {
2564 if (C->getValue() == 0) {
2565 _trap();
2566 return;
2567 }
2568 }
2569 div0Check(IceType_i64, loOperand(Src1), hiOperand(Src1));
2570 return;
2571 }
2572 case IceType_i32: {
2573 // Src0 and Src1 have already been appropriately extended to an i32, so we
2574 // don't check for i8 and i16.
2575 if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
2576 if (C->getValue() == 0) {
2577 _trap();
2578 return;
2579 }
2580 }
2581 div0Check(IceType_i32, Src1, nullptr);
2582 return;
2583 }
2584 }
2585}
2586
John Portoccea7932015-11-17 04:58:36 -08002587void TargetARM32::lowerInt64Arithmetic(InstArithmetic::OpKind Op,
2588 Variable *Dest, Operand *Src0,
2589 Operand *Src1) {
2590 Int32Operands SrcsLo(loOperand(Src0), loOperand(Src1));
2591 Int32Operands SrcsHi(hiOperand(Src0), hiOperand(Src1));
2592 assert(SrcsLo.swappedOperands() == SrcsHi.swappedOperands());
2593 assert(SrcsLo.hasConstOperand() == SrcsHi.hasConstOperand());
2594
Jim Stichnoth54f3d512015-12-11 09:53:00 -08002595 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
2596 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
John Portoccea7932015-11-17 04:58:36 -08002597 Variable *T_Lo = makeReg(DestLo->getType());
2598 Variable *T_Hi = makeReg(DestHi->getType());
2599
2600 switch (Op) {
2601 case InstArithmetic::_num:
2602 llvm::report_fatal_error("Unknown arithmetic operator");
2603 return;
2604 case InstArithmetic::Add: {
2605 Variable *Src0LoR = SrcsLo.src0R(this);
2606 Operand *Src1LoRF = SrcsLo.src1RF(this);
2607 Variable *Src0HiR = SrcsHi.src0R(this);
2608 Operand *Src1HiRF = SrcsHi.src1RF(this);
2609 _adds(T_Lo, Src0LoR, Src1LoRF);
2610 _mov(DestLo, T_Lo);
2611 _adc(T_Hi, Src0HiR, Src1HiRF);
2612 _mov(DestHi, T_Hi);
2613 return;
2614 }
2615 case InstArithmetic::And: {
2616 Variable *Src0LoR = SrcsLo.src0R(this);
2617 Operand *Src1LoRF = SrcsLo.src1RF(this);
2618 Variable *Src0HiR = SrcsHi.src0R(this);
2619 Operand *Src1HiRF = SrcsHi.src1RF(this);
2620 _and(T_Lo, Src0LoR, Src1LoRF);
2621 _mov(DestLo, T_Lo);
2622 _and(T_Hi, Src0HiR, Src1HiRF);
2623 _mov(DestHi, T_Hi);
2624 return;
2625 }
2626 case InstArithmetic::Or: {
2627 Variable *Src0LoR = SrcsLo.src0R(this);
2628 Operand *Src1LoRF = SrcsLo.src1RF(this);
2629 Variable *Src0HiR = SrcsHi.src0R(this);
2630 Operand *Src1HiRF = SrcsHi.src1RF(this);
2631 _orr(T_Lo, Src0LoR, Src1LoRF);
2632 _mov(DestLo, T_Lo);
2633 _orr(T_Hi, Src0HiR, Src1HiRF);
2634 _mov(DestHi, T_Hi);
2635 return;
2636 }
2637 case InstArithmetic::Xor: {
2638 Variable *Src0LoR = SrcsLo.src0R(this);
2639 Operand *Src1LoRF = SrcsLo.src1RF(this);
2640 Variable *Src0HiR = SrcsHi.src0R(this);
2641 Operand *Src1HiRF = SrcsHi.src1RF(this);
2642 _eor(T_Lo, Src0LoR, Src1LoRF);
2643 _mov(DestLo, T_Lo);
2644 _eor(T_Hi, Src0HiR, Src1HiRF);
2645 _mov(DestHi, T_Hi);
2646 return;
2647 }
2648 case InstArithmetic::Sub: {
2649 Variable *Src0LoR = SrcsLo.src0R(this);
2650 Operand *Src1LoRF = SrcsLo.src1RF(this);
2651 Variable *Src0HiR = SrcsHi.src0R(this);
2652 Operand *Src1HiRF = SrcsHi.src1RF(this);
2653 if (SrcsLo.swappedOperands()) {
2654 _rsbs(T_Lo, Src0LoR, Src1LoRF);
2655 _mov(DestLo, T_Lo);
2656 _rsc(T_Hi, Src0HiR, Src1HiRF);
2657 _mov(DestHi, T_Hi);
2658 } else {
2659 _subs(T_Lo, Src0LoR, Src1LoRF);
2660 _mov(DestLo, T_Lo);
2661 _sbc(T_Hi, Src0HiR, Src1HiRF);
2662 _mov(DestHi, T_Hi);
2663 }
2664 return;
2665 }
2666 case InstArithmetic::Mul: {
2667 // GCC 4.8 does:
2668 // a=b*c ==>
2669 // t_acc =(mul) (b.lo * c.hi)
2670 // t_acc =(mla) (c.lo * b.hi) + t_acc
2671 // t.hi,t.lo =(umull) b.lo * c.lo
2672 // t.hi += t_acc
2673 // a.lo = t.lo
2674 // a.hi = t.hi
2675 //
2676 // LLVM does:
2677 // t.hi,t.lo =(umull) b.lo * c.lo
2678 // t.hi =(mla) (b.lo * c.hi) + t.hi
2679 // t.hi =(mla) (b.hi * c.lo) + t.hi
2680 // a.lo = t.lo
2681 // a.hi = t.hi
2682 //
2683 // LLVM's lowering has fewer instructions, but more register pressure:
2684 // t.lo is live from beginning to end, while GCC delays the two-dest
2685 // instruction till the end, and kills c.hi immediately.
2686 Variable *T_Acc = makeReg(IceType_i32);
2687 Variable *T_Acc1 = makeReg(IceType_i32);
2688 Variable *T_Hi1 = makeReg(IceType_i32);
2689 Variable *Src0RLo = SrcsLo.unswappedSrc0R(this);
2690 Variable *Src0RHi = SrcsHi.unswappedSrc0R(this);
2691 Variable *Src1RLo = SrcsLo.unswappedSrc1R(this);
2692 Variable *Src1RHi = SrcsHi.unswappedSrc1R(this);
2693 _mul(T_Acc, Src0RLo, Src1RHi);
2694 _mla(T_Acc1, Src1RLo, Src0RHi, T_Acc);
2695 _umull(T_Lo, T_Hi1, Src0RLo, Src1RLo);
2696 _add(T_Hi, T_Hi1, T_Acc1);
2697 _mov(DestLo, T_Lo);
2698 _mov(DestHi, T_Hi);
2699 return;
2700 }
2701 case InstArithmetic::Shl: {
2702 if (!SrcsLo.swappedOperands() && SrcsLo.hasConstOperand()) {
2703 Variable *Src0RLo = SrcsLo.src0R(this);
2704 // Truncating the ShAmt to [0, 63] because that's what ARM does anyway.
2705 const int32_t ShAmtImm = SrcsLo.getConstantValue() & 0x3F;
2706 if (ShAmtImm == 0) {
2707 _mov(DestLo, Src0RLo);
2708 _mov(DestHi, SrcsHi.src0R(this));
2709 return;
2710 }
2711
2712 if (ShAmtImm >= 32) {
2713 if (ShAmtImm == 32) {
2714 _mov(DestHi, Src0RLo);
2715 } else {
John Porto2758bb02015-11-17 14:31:25 -08002716 Operand *ShAmtOp = shAmtImm(ShAmtImm - 32);
John Portoccea7932015-11-17 04:58:36 -08002717 _lsl(T_Hi, Src0RLo, ShAmtOp);
2718 _mov(DestHi, T_Hi);
2719 }
2720
2721 Operand *_0 =
2722 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
2723 _mov(T_Lo, _0);
2724 _mov(DestLo, T_Lo);
2725 return;
2726 }
2727
2728 Variable *Src0RHi = SrcsHi.src0R(this);
John Porto2758bb02015-11-17 14:31:25 -08002729 Operand *ShAmtOp = shAmtImm(ShAmtImm);
2730 Operand *ComplShAmtOp = shAmtImm(32 - ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002731 _lsl(T_Hi, Src0RHi, ShAmtOp);
2732 _orr(T_Hi, T_Hi,
2733 OperandARM32FlexReg::create(Func, IceType_i32, Src0RLo,
2734 OperandARM32::LSR, ComplShAmtOp));
2735 _mov(DestHi, T_Hi);
2736
2737 _lsl(T_Lo, Src0RLo, ShAmtOp);
2738 _mov(DestLo, T_Lo);
2739 return;
2740 }
2741
2742 // a=b<<c ==>
2743 // pnacl-llc does:
2744 // mov t_b.lo, b.lo
2745 // mov t_b.hi, b.hi
2746 // mov t_c.lo, c.lo
2747 // rsb T0, t_c.lo, #32
2748 // lsr T1, t_b.lo, T0
2749 // orr t_a.hi, T1, t_b.hi, lsl t_c.lo
2750 // sub T2, t_c.lo, #32
2751 // cmp T2, #0
2752 // lslge t_a.hi, t_b.lo, T2
2753 // lsl t_a.lo, t_b.lo, t_c.lo
2754 // mov a.lo, t_a.lo
2755 // mov a.hi, t_a.hi
2756 //
2757 // GCC 4.8 does:
2758 // sub t_c1, c.lo, #32
2759 // lsl t_hi, b.hi, c.lo
2760 // orr t_hi, t_hi, b.lo, lsl t_c1
2761 // rsb t_c2, c.lo, #32
2762 // orr t_hi, t_hi, b.lo, lsr t_c2
2763 // lsl t_lo, b.lo, c.lo
2764 // a.lo = t_lo
2765 // a.hi = t_hi
2766 //
2767 // These are incompatible, therefore we mimic pnacl-llc.
2768 // Can be strength-reduced for constant-shifts, but we don't do that for
2769 // now.
2770 // Given the sub/rsb T_C, C.lo, #32, one of the T_C will be negative. On
2771 // ARM, shifts only take the lower 8 bits of the shift register, and
2772 // saturate to the range 0-32, so the negative value will saturate to 32.
2773 Operand *_32 = legalize(Ctx->getConstantInt32(32), Legal_Reg | Legal_Flex);
2774 Operand *_0 =
2775 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
2776 Variable *T0 = makeReg(IceType_i32);
2777 Variable *T1 = makeReg(IceType_i32);
2778 Variable *T2 = makeReg(IceType_i32);
2779 Variable *TA_Hi = makeReg(IceType_i32);
2780 Variable *TA_Lo = makeReg(IceType_i32);
John Portoa1cdd572016-03-01 15:19:29 -08002781 Variable *Src0RLo = SrcsLo.unswappedSrc0R(this);
John Portoccea7932015-11-17 04:58:36 -08002782 Variable *Src0RHi = SrcsHi.unswappedSrc0R(this);
2783 Variable *Src1RLo = SrcsLo.unswappedSrc1R(this);
2784 _rsb(T0, Src1RLo, _32);
2785 _lsr(T1, Src0RLo, T0);
2786 _orr(TA_Hi, T1, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
2787 OperandARM32::LSL, Src1RLo));
2788 _sub(T2, Src1RLo, _32);
2789 _cmp(T2, _0);
2790 _lsl(TA_Hi, Src0RLo, T2, CondARM32::GE);
2791 _set_dest_redefined();
2792 _lsl(TA_Lo, Src0RLo, Src1RLo);
2793 _mov(DestLo, TA_Lo);
2794 _mov(DestHi, TA_Hi);
2795 return;
2796 }
2797 case InstArithmetic::Lshr:
2798 case InstArithmetic::Ashr: {
2799 const bool ASR = Op == InstArithmetic::Ashr;
2800 if (!SrcsLo.swappedOperands() && SrcsLo.hasConstOperand()) {
2801 Variable *Src0RHi = SrcsHi.src0R(this);
2802 // Truncating the ShAmt to [0, 63] because that's what ARM does anyway.
John Porto2758bb02015-11-17 14:31:25 -08002803 const int32_t ShAmt = SrcsLo.getConstantValue() & 0x3F;
2804 if (ShAmt == 0) {
John Portoccea7932015-11-17 04:58:36 -08002805 _mov(DestHi, Src0RHi);
2806 _mov(DestLo, SrcsLo.src0R(this));
2807 return;
2808 }
2809
John Porto2758bb02015-11-17 14:31:25 -08002810 if (ShAmt >= 32) {
2811 if (ShAmt == 32) {
John Portoccea7932015-11-17 04:58:36 -08002812 _mov(DestLo, Src0RHi);
2813 } else {
John Porto2758bb02015-11-17 14:31:25 -08002814 Operand *ShAmtImm = shAmtImm(ShAmt - 32);
John Portoccea7932015-11-17 04:58:36 -08002815 if (ASR) {
John Porto2758bb02015-11-17 14:31:25 -08002816 _asr(T_Lo, Src0RHi, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002817 } else {
John Porto2758bb02015-11-17 14:31:25 -08002818 _lsr(T_Lo, Src0RHi, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002819 }
2820 _mov(DestLo, T_Lo);
2821 }
2822
2823 if (ASR) {
John Porto2758bb02015-11-17 14:31:25 -08002824 Operand *_31 = shAmtImm(31);
John Portoccea7932015-11-17 04:58:36 -08002825 _asr(T_Hi, Src0RHi, _31);
2826 } else {
2827 Operand *_0 = legalize(Ctx->getConstantZero(IceType_i32),
2828 Legal_Reg | Legal_Flex);
2829 _mov(T_Hi, _0);
2830 }
2831 _mov(DestHi, T_Hi);
2832 return;
2833 }
2834
2835 Variable *Src0RLo = SrcsLo.src0R(this);
John Porto2758bb02015-11-17 14:31:25 -08002836 Operand *ShAmtImm = shAmtImm(ShAmt);
2837 Operand *ComplShAmtImm = shAmtImm(32 - ShAmt);
2838 _lsr(T_Lo, Src0RLo, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002839 _orr(T_Lo, T_Lo,
2840 OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
John Porto2758bb02015-11-17 14:31:25 -08002841 OperandARM32::LSL, ComplShAmtImm));
John Portoccea7932015-11-17 04:58:36 -08002842 _mov(DestLo, T_Lo);
2843
2844 if (ASR) {
John Porto2758bb02015-11-17 14:31:25 -08002845 _asr(T_Hi, Src0RHi, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002846 } else {
John Porto2758bb02015-11-17 14:31:25 -08002847 _lsr(T_Hi, Src0RHi, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08002848 }
2849 _mov(DestHi, T_Hi);
2850 return;
2851 }
2852
2853 // a=b>>c
2854 // pnacl-llc does:
2855 // mov t_b.lo, b.lo
2856 // mov t_b.hi, b.hi
2857 // mov t_c.lo, c.lo
2858 // lsr T0, t_b.lo, t_c.lo
2859 // rsb T1, t_c.lo, #32
2860 // orr t_a.lo, T0, t_b.hi, lsl T1
2861 // sub T2, t_c.lo, #32
2862 // cmp T2, #0
2863 // [al]srge t_a.lo, t_b.hi, T2
2864 // [al]sr t_a.hi, t_b.hi, t_c.lo
2865 // mov a.lo, t_a.lo
2866 // mov a.hi, t_a.hi
2867 //
2868 // GCC 4.8 does (lsr):
2869 // rsb t_c1, c.lo, #32
2870 // lsr t_lo, b.lo, c.lo
2871 // orr t_lo, t_lo, b.hi, lsl t_c1
2872 // sub t_c2, c.lo, #32
2873 // orr t_lo, t_lo, b.hi, lsr t_c2
2874 // lsr t_hi, b.hi, c.lo
2875 // mov a.lo, t_lo
2876 // mov a.hi, t_hi
2877 //
2878 // These are incompatible, therefore we mimic pnacl-llc.
2879 Operand *_32 = legalize(Ctx->getConstantInt32(32), Legal_Reg | Legal_Flex);
2880 Operand *_0 =
2881 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
2882 Variable *T0 = makeReg(IceType_i32);
2883 Variable *T1 = makeReg(IceType_i32);
2884 Variable *T2 = makeReg(IceType_i32);
2885 Variable *TA_Lo = makeReg(IceType_i32);
2886 Variable *TA_Hi = makeReg(IceType_i32);
2887 Variable *Src0RLo = SrcsLo.unswappedSrc0R(this);
2888 Variable *Src0RHi = SrcsHi.unswappedSrc0R(this);
2889 Variable *Src1RLo = SrcsLo.unswappedSrc1R(this);
2890 _lsr(T0, Src0RLo, Src1RLo);
2891 _rsb(T1, Src1RLo, _32);
2892 _orr(TA_Lo, T0, OperandARM32FlexReg::create(Func, IceType_i32, Src0RHi,
2893 OperandARM32::LSL, T1));
2894 _sub(T2, Src1RLo, _32);
2895 _cmp(T2, _0);
2896 if (ASR) {
2897 _asr(TA_Lo, Src0RHi, T2, CondARM32::GE);
2898 _set_dest_redefined();
2899 _asr(TA_Hi, Src0RHi, Src1RLo);
2900 } else {
2901 _lsr(TA_Lo, Src0RHi, T2, CondARM32::GE);
2902 _set_dest_redefined();
2903 _lsr(TA_Hi, Src0RHi, Src1RLo);
2904 }
2905 _mov(DestLo, TA_Lo);
2906 _mov(DestHi, TA_Hi);
2907 return;
2908 }
2909 case InstArithmetic::Fadd:
2910 case InstArithmetic::Fsub:
2911 case InstArithmetic::Fmul:
2912 case InstArithmetic::Fdiv:
2913 case InstArithmetic::Frem:
2914 llvm::report_fatal_error("FP instruction with i64 type");
2915 return;
2916 case InstArithmetic::Udiv:
2917 case InstArithmetic::Sdiv:
2918 case InstArithmetic::Urem:
2919 case InstArithmetic::Srem:
2920 llvm::report_fatal_error("Call-helper-involved instruction for i64 type "
2921 "should have already been handled before");
2922 return;
2923 }
2924}
2925
John Porto98cc08c2015-11-24 12:30:01 -08002926namespace {
2927// StrengthReduction is a namespace with the strength reduction machinery. The
2928// entry point is the StrengthReduction::tryToOptimize method. It returns true
2929// if the optimization can be performed, and false otherwise.
2930//
2931// If the optimization can be performed, tryToOptimize sets its NumOperations
2932// parameter to the number of shifts that are needed to perform the
2933// multiplication; and it sets the Operations parameter with <ShAmt, AddOrSub>
2934// tuples that describe how to materialize the multiplication.
2935//
2936// The algorithm finds contiguous 1s in the Multiplication source, and uses one
2937// or two shifts to materialize it. A sequence of 1s, e.g.,
2938//
2939// M N
2940// ...00000000000011111...111110000000...
2941//
2942// is materializable with (1 << (M + 1)) - (1 << N):
2943//
2944// ...00000000000100000...000000000000... [1 << (M + 1)]
2945// ...00000000000000000...000010000000... (-) [1 << N]
2946// --------------------------------------
2947// ...00000000000011111...111110000000...
2948//
2949// And a single bit set, which is just a left shift.
2950namespace StrengthReduction {
2951enum AggregationOperation {
2952 AO_Invalid,
2953 AO_Add,
2954 AO_Sub,
2955};
2956
2957// AggregateElement is a glorified <ShAmt, AddOrSub> tuple.
2958class AggregationElement {
2959 AggregationElement(const AggregationElement &) = delete;
2960
2961public:
2962 AggregationElement() = default;
2963 AggregationElement &operator=(const AggregationElement &) = default;
2964 AggregationElement(AggregationOperation Op, uint32_t ShAmt)
2965 : Op(Op), ShAmt(ShAmt) {}
2966
2967 Operand *createShiftedOperand(Cfg *Func, Variable *OpR) const {
2968 assert(OpR->mustHaveReg());
2969 if (ShAmt == 0) {
2970 return OpR;
2971 }
2972 return OperandARM32FlexReg::create(
2973 Func, IceType_i32, OpR, OperandARM32::LSL,
2974 OperandARM32ShAmtImm::create(
2975 Func, llvm::cast<ConstantInteger32>(
2976 Func->getContext()->getConstantInt32(ShAmt))));
2977 }
2978
2979 bool aggregateWithAdd() const {
2980 switch (Op) {
2981 case AO_Invalid:
2982 llvm::report_fatal_error("Invalid Strength Reduction Operations.");
2983 case AO_Add:
2984 return true;
2985 case AO_Sub:
2986 return false;
2987 }
Jim Stichnothb0051df2016-01-13 11:39:15 -08002988 llvm_unreachable("(silence g++ warning)");
John Porto98cc08c2015-11-24 12:30:01 -08002989 }
2990
2991 uint32_t shAmt() const { return ShAmt; }
2992
2993private:
2994 AggregationOperation Op = AO_Invalid;
2995 uint32_t ShAmt;
2996};
2997
2998// [RangeStart, RangeEnd] is a range of 1s in Src.
2999template <std::size_t N>
3000bool addOperations(uint32_t RangeStart, uint32_t RangeEnd, SizeT *NumOperations,
3001 std::array<AggregationElement, N> *Operations) {
3002 assert(*NumOperations < N);
3003 if (RangeStart == RangeEnd) {
3004 // Single bit set:
3005 // Src : 0...00010...
3006 // RangeStart : ^
3007 // RangeEnd : ^
3008 // NegSrc : 0...00001...
3009 (*Operations)[*NumOperations] = AggregationElement(AO_Add, RangeStart);
3010 ++(*NumOperations);
3011 return true;
3012 }
3013
3014 // Sequence of 1s: (two operations required.)
3015 // Src : 0...00011...110...
3016 // RangeStart : ^
3017 // RangeEnd : ^
3018 // NegSrc : 0...00000...001...
3019 if (*NumOperations + 1 >= N) {
3020 return false;
3021 }
3022 (*Operations)[*NumOperations] = AggregationElement(AO_Add, RangeStart + 1);
3023 ++(*NumOperations);
3024 (*Operations)[*NumOperations] = AggregationElement(AO_Sub, RangeEnd);
3025 ++(*NumOperations);
3026 return true;
3027}
3028
3029// tryToOptmize scans Src looking for sequences of 1s (including the unitary bit
3030// 1 surrounded by zeroes.
3031template <std::size_t N>
3032bool tryToOptimize(uint32_t Src, SizeT *NumOperations,
3033 std::array<AggregationElement, N> *Operations) {
3034 constexpr uint32_t SrcSizeBits = sizeof(Src) * CHAR_BIT;
3035 uint32_t NegSrc = ~Src;
3036
3037 *NumOperations = 0;
3038 while (Src != 0 && *NumOperations < N) {
3039 // Each step of the algorithm:
3040 // * finds L, the last bit set in Src;
3041 // * clears all the upper bits in NegSrc up to bit L;
3042 // * finds nL, the last bit set in NegSrc;
3043 // * clears all the upper bits in Src up to bit nL;
3044 //
3045 // if L == nL + 1, then a unitary 1 was found in Src. Otherwise, a sequence
3046 // of 1s starting at L, and ending at nL + 1, was found.
3047 const uint32_t SrcLastBitSet = llvm::findLastSet(Src);
3048 const uint32_t NegSrcClearMask =
3049 (SrcLastBitSet == 0) ? 0
3050 : (0xFFFFFFFFu) >> (SrcSizeBits - SrcLastBitSet);
3051 NegSrc &= NegSrcClearMask;
3052 if (NegSrc == 0) {
3053 if (addOperations(SrcLastBitSet, 0, NumOperations, Operations)) {
3054 return true;
3055 }
3056 return false;
3057 }
3058 const uint32_t NegSrcLastBitSet = llvm::findLastSet(NegSrc);
3059 assert(NegSrcLastBitSet < SrcLastBitSet);
3060 const uint32_t SrcClearMask =
3061 (NegSrcLastBitSet == 0) ? 0 : (0xFFFFFFFFu) >>
3062 (SrcSizeBits - NegSrcLastBitSet);
3063 Src &= SrcClearMask;
3064 if (!addOperations(SrcLastBitSet, NegSrcLastBitSet + 1, NumOperations,
3065 Operations)) {
3066 return false;
3067 }
3068 }
3069
3070 return Src == 0;
3071}
3072} // end of namespace StrengthReduction
3073} // end of anonymous namespace
3074
John Portoeb13acc2015-12-09 05:10:58 -08003075void TargetARM32::lowerArithmetic(const InstArithmetic *Instr) {
3076 Variable *Dest = Instr->getDest();
John Porto614140e2015-11-23 11:43:13 -08003077
3078 if (Dest->isRematerializable()) {
John Porto1d937a82015-12-17 06:19:34 -08003079 Context.insert<InstFakeDef>(Dest);
John Porto614140e2015-11-23 11:43:13 -08003080 return;
3081 }
3082
John Porto98cc08c2015-11-24 12:30:01 -08003083 Type DestTy = Dest->getType();
3084 if (DestTy == IceType_i1) {
John Portoeb13acc2015-12-09 05:10:58 -08003085 lowerInt1Arithmetic(Instr);
John Porto7b3d9cb2015-11-11 14:26:57 -08003086 return;
3087 }
3088
John Portoeb13acc2015-12-09 05:10:58 -08003089 Operand *Src0 = legalizeUndef(Instr->getSrc(0));
3090 Operand *Src1 = legalizeUndef(Instr->getSrc(1));
John Porto98cc08c2015-11-24 12:30:01 -08003091 if (DestTy == IceType_i64) {
John Portoeb13acc2015-12-09 05:10:58 -08003092 lowerInt64Arithmetic(Instr->getOp(), Instr->getDest(), Src0, Src1);
Jan Voung70fa5252015-07-06 14:01:25 -07003093 return;
John Portoccea7932015-11-17 04:58:36 -08003094 }
3095
John Porto98cc08c2015-11-24 12:30:01 -08003096 if (isVectorType(DestTy)) {
Eric Holk40c69b42016-01-26 10:10:39 -08003097 switch (Instr->getOp()) {
3098 default:
3099 UnimplementedLoweringError(this, Instr);
3100 return;
3101 // Explicitly whitelist vector instructions we have implemented/enabled.
Eric Holk40c69b42016-01-26 10:10:39 -08003102 case InstArithmetic::Add:
Eric Holkb58170c2016-01-27 11:18:29 -08003103 case InstArithmetic::And:
John Porto15e77d42016-04-13 12:57:14 -07003104 case InstArithmetic::Ashr:
3105 case InstArithmetic::Fadd:
Eric Holk029bed92016-01-28 13:38:43 -08003106 case InstArithmetic::Fmul:
John Porto15e77d42016-04-13 12:57:14 -07003107 case InstArithmetic::Fsub:
3108 case InstArithmetic::Lshr:
Eric Holk029bed92016-01-28 13:38:43 -08003109 case InstArithmetic::Mul:
John Porto15e77d42016-04-13 12:57:14 -07003110 case InstArithmetic::Or:
3111 case InstArithmetic::Shl:
3112 case InstArithmetic::Sub:
3113 case InstArithmetic::Xor:
Eric Holk40c69b42016-01-26 10:10:39 -08003114 break;
3115 }
Jan Voung70fa5252015-07-06 14:01:25 -07003116 }
John Portoccea7932015-11-17 04:58:36 -08003117
John Porto98cc08c2015-11-24 12:30:01 -08003118 Variable *T = makeReg(DestTy);
John Portoccea7932015-11-17 04:58:36 -08003119
3120 // * Handle div/rem separately. They require a non-legalized Src1 to inspect
Jan Voung70fa5252015-07-06 14:01:25 -07003121 // whether or not Src1 is a non-zero constant. Once legalized it is more
3122 // difficult to determine (constant may be moved to a register).
John Portoccea7932015-11-17 04:58:36 -08003123 // * Handle floating point arithmetic separately: they require Src1 to be
3124 // legalized to a register.
John Portoeb13acc2015-12-09 05:10:58 -08003125 switch (Instr->getOp()) {
Jan Voung70fa5252015-07-06 14:01:25 -07003126 default:
3127 break;
3128 case InstArithmetic::Udiv: {
John Portoafc92af2015-10-16 10:34:04 -07003129 constexpr bool NotRemainder = false;
John Portoccea7932015-11-17 04:58:36 -08003130 Variable *Src0R = legalizeToReg(Src0);
Jan Voung70fa5252015-07-06 14:01:25 -07003131 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv,
John Portoc39ec102015-12-01 13:00:43 -08003132 NotRemainder);
Jan Voung70fa5252015-07-06 14:01:25 -07003133 return;
3134 }
3135 case InstArithmetic::Sdiv: {
John Portoafc92af2015-10-16 10:34:04 -07003136 constexpr bool NotRemainder = false;
John Portoccea7932015-11-17 04:58:36 -08003137 Variable *Src0R = legalizeToReg(Src0);
Jan Voung70fa5252015-07-06 14:01:25 -07003138 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv,
John Portoc39ec102015-12-01 13:00:43 -08003139 NotRemainder);
Jan Voung70fa5252015-07-06 14:01:25 -07003140 return;
3141 }
3142 case InstArithmetic::Urem: {
3143 constexpr bool IsRemainder = true;
John Portoccea7932015-11-17 04:58:36 -08003144 Variable *Src0R = legalizeToReg(Src0);
Jan Voung70fa5252015-07-06 14:01:25 -07003145 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_uxt, &TargetARM32::_udiv,
John Portoc39ec102015-12-01 13:00:43 -08003146 IsRemainder);
Jan Voung70fa5252015-07-06 14:01:25 -07003147 return;
3148 }
3149 case InstArithmetic::Srem: {
3150 constexpr bool IsRemainder = true;
John Portoccea7932015-11-17 04:58:36 -08003151 Variable *Src0R = legalizeToReg(Src0);
Jan Voung70fa5252015-07-06 14:01:25 -07003152 lowerIDivRem(Dest, T, Src0R, Src1, &TargetARM32::_sxt, &TargetARM32::_sdiv,
John Portoc39ec102015-12-01 13:00:43 -08003153 IsRemainder);
Jan Voung70fa5252015-07-06 14:01:25 -07003154 return;
3155 }
Jan Voung86ebec12015-08-09 07:58:35 -07003156 case InstArithmetic::Frem: {
John Portoc39ec102015-12-01 13:00:43 -08003157 if (!isScalarFloatingType(DestTy)) {
3158 llvm::report_fatal_error("Unexpected type when lowering frem.");
3159 }
3160 llvm::report_fatal_error("Frem should have already been lowered.");
Jan Voung86ebec12015-08-09 07:58:35 -07003161 }
Jan Voung86ebec12015-08-09 07:58:35 -07003162 case InstArithmetic::Fadd: {
John Portoccea7932015-11-17 04:58:36 -08003163 Variable *Src0R = legalizeToReg(Src0);
John Portoeb13acc2015-12-09 05:10:58 -08003164 if (const Inst *Src1Producer = Computations.getProducerOf(Src1)) {
3165 Variable *Src1R = legalizeToReg(Src1Producer->getSrc(0));
3166 Variable *Src2R = legalizeToReg(Src1Producer->getSrc(1));
3167 _vmla(Src0R, Src1R, Src2R);
3168 _mov(Dest, Src0R);
3169 return;
3170 }
3171
Jan Voung86ebec12015-08-09 07:58:35 -07003172 Variable *Src1R = legalizeToReg(Src1);
3173 _vadd(T, Src0R, Src1R);
John Portoba6a67c2015-09-25 15:19:45 -07003174 _mov(Dest, T);
Jan Voung86ebec12015-08-09 07:58:35 -07003175 return;
3176 }
3177 case InstArithmetic::Fsub: {
John Portoccea7932015-11-17 04:58:36 -08003178 Variable *Src0R = legalizeToReg(Src0);
John Portoeb13acc2015-12-09 05:10:58 -08003179 if (const Inst *Src1Producer = Computations.getProducerOf(Src1)) {
3180 Variable *Src1R = legalizeToReg(Src1Producer->getSrc(0));
3181 Variable *Src2R = legalizeToReg(Src1Producer->getSrc(1));
3182 _vmls(Src0R, Src1R, Src2R);
3183 _mov(Dest, Src0R);
3184 return;
3185 }
Jan Voung86ebec12015-08-09 07:58:35 -07003186 Variable *Src1R = legalizeToReg(Src1);
3187 _vsub(T, Src0R, Src1R);
John Portoba6a67c2015-09-25 15:19:45 -07003188 _mov(Dest, T);
Jan Voung86ebec12015-08-09 07:58:35 -07003189 return;
3190 }
3191 case InstArithmetic::Fmul: {
John Portoccea7932015-11-17 04:58:36 -08003192 Variable *Src0R = legalizeToReg(Src0);
Jan Voung86ebec12015-08-09 07:58:35 -07003193 Variable *Src1R = legalizeToReg(Src1);
3194 _vmul(T, Src0R, Src1R);
John Portoba6a67c2015-09-25 15:19:45 -07003195 _mov(Dest, T);
Jan Voung86ebec12015-08-09 07:58:35 -07003196 return;
3197 }
3198 case InstArithmetic::Fdiv: {
John Portoccea7932015-11-17 04:58:36 -08003199 Variable *Src0R = legalizeToReg(Src0);
Jan Voung86ebec12015-08-09 07:58:35 -07003200 Variable *Src1R = legalizeToReg(Src1);
3201 _vdiv(T, Src0R, Src1R);
John Portoba6a67c2015-09-25 15:19:45 -07003202 _mov(Dest, T);
Jan Voung86ebec12015-08-09 07:58:35 -07003203 return;
3204 }
Jan Voung70fa5252015-07-06 14:01:25 -07003205 }
3206
John Portoccea7932015-11-17 04:58:36 -08003207 // Handle everything else here.
3208 Int32Operands Srcs(Src0, Src1);
John Portoeb13acc2015-12-09 05:10:58 -08003209 switch (Instr->getOp()) {
Jan Voung70fa5252015-07-06 14:01:25 -07003210 case InstArithmetic::_num:
John Portoccea7932015-11-17 04:58:36 -08003211 llvm::report_fatal_error("Unknown arithmetic operator");
Jan Voung70fa5252015-07-06 14:01:25 -07003212 return;
John Portoccea7932015-11-17 04:58:36 -08003213 case InstArithmetic::Add: {
John Portoeb13acc2015-12-09 05:10:58 -08003214 if (const Inst *Src1Producer = Computations.getProducerOf(Src1)) {
Eric Holk40c69b42016-01-26 10:10:39 -08003215 assert(!isVectorType(DestTy));
John Portoeb13acc2015-12-09 05:10:58 -08003216 Variable *Src0R = legalizeToReg(Src0);
3217 Variable *Src1R = legalizeToReg(Src1Producer->getSrc(0));
3218 Variable *Src2R = legalizeToReg(Src1Producer->getSrc(1));
3219 _mla(T, Src1R, Src2R, Src0R);
3220 _mov(Dest, T);
3221 return;
3222 }
3223
John Portoccea7932015-11-17 04:58:36 -08003224 if (Srcs.hasConstOperand()) {
3225 if (!Srcs.immediateIsFlexEncodable() &&
3226 Srcs.negatedImmediateIsFlexEncodable()) {
Eric Holk40c69b42016-01-26 10:10:39 -08003227 assert(!isVectorType(DestTy));
John Portoccea7932015-11-17 04:58:36 -08003228 Variable *Src0R = Srcs.src0R(this);
3229 Operand *Src1F = Srcs.negatedSrc1F(this);
3230 if (!Srcs.swappedOperands()) {
3231 _sub(T, Src0R, Src1F);
3232 } else {
3233 _rsb(T, Src0R, Src1F);
3234 }
3235 _mov(Dest, T);
3236 return;
3237 }
3238 }
3239 Variable *Src0R = Srcs.src0R(this);
Eric Holk40c69b42016-01-26 10:10:39 -08003240 if (isVectorType(DestTy)) {
3241 Variable *Src1R = legalizeToReg(Src1);
3242 _vadd(T, Src0R, Src1R);
3243 } else {
3244 Operand *Src1RF = Srcs.src1RF(this);
3245 _add(T, Src0R, Src1RF);
3246 }
Jan Voung70fa5252015-07-06 14:01:25 -07003247 _mov(Dest, T);
3248 return;
John Portoccea7932015-11-17 04:58:36 -08003249 }
3250 case InstArithmetic::And: {
3251 if (Srcs.hasConstOperand()) {
3252 if (!Srcs.immediateIsFlexEncodable() &&
3253 Srcs.invertedImmediateIsFlexEncodable()) {
3254 Variable *Src0R = Srcs.src0R(this);
3255 Operand *Src1F = Srcs.invertedSrc1F(this);
3256 _bic(T, Src0R, Src1F);
3257 _mov(Dest, T);
3258 return;
3259 }
3260 }
Karl Schimpffd7975f2016-02-02 11:25:10 -08003261 assert(isIntegerType(DestTy));
John Portoccea7932015-11-17 04:58:36 -08003262 Variable *Src0R = Srcs.src0R(this);
Eric Holkb58170c2016-01-27 11:18:29 -08003263 if (isVectorType(DestTy)) {
3264 Variable *Src1R = legalizeToReg(Src1);
3265 _vand(T, Src0R, Src1R);
3266 } else {
3267 Operand *Src1RF = Srcs.src1RF(this);
3268 _and(T, Src0R, Src1RF);
3269 }
Jan Voung70fa5252015-07-06 14:01:25 -07003270 _mov(Dest, T);
3271 return;
John Portoccea7932015-11-17 04:58:36 -08003272 }
3273 case InstArithmetic::Or: {
3274 Variable *Src0R = Srcs.src0R(this);
Karl Schimpfe2955752016-02-02 12:57:30 -08003275 assert(isIntegerType(DestTy));
Eric Holkcad0b752016-01-27 14:56:22 -08003276 if (isVectorType(DestTy)) {
3277 Variable *Src1R = legalizeToReg(Src1);
3278 _vorr(T, Src0R, Src1R);
3279 } else {
3280 Operand *Src1RF = Srcs.src1RF(this);
3281 _orr(T, Src0R, Src1RF);
3282 }
Jan Voung70fa5252015-07-06 14:01:25 -07003283 _mov(Dest, T);
3284 return;
John Portoccea7932015-11-17 04:58:36 -08003285 }
3286 case InstArithmetic::Xor: {
3287 Variable *Src0R = Srcs.src0R(this);
Karl Schimpf625dfb32016-02-03 13:21:50 -08003288 assert(isIntegerType(DestTy));
Eric Holk76108e92016-01-28 13:37:50 -08003289 if (isVectorType(DestTy)) {
3290 Variable *Src1R = legalizeToReg(Src1);
3291 _veor(T, Src0R, Src1R);
3292 } else {
3293 Operand *Src1RF = Srcs.src1RF(this);
3294 _eor(T, Src0R, Src1RF);
3295 }
Jan Voung70fa5252015-07-06 14:01:25 -07003296 _mov(Dest, T);
3297 return;
John Portoccea7932015-11-17 04:58:36 -08003298 }
3299 case InstArithmetic::Sub: {
John Portoeb13acc2015-12-09 05:10:58 -08003300 if (const Inst *Src1Producer = Computations.getProducerOf(Src1)) {
Eric Holke5727b82016-01-27 11:08:48 -08003301 assert(!isVectorType(DestTy));
John Portoeb13acc2015-12-09 05:10:58 -08003302 Variable *Src0R = legalizeToReg(Src0);
3303 Variable *Src1R = legalizeToReg(Src1Producer->getSrc(0));
3304 Variable *Src2R = legalizeToReg(Src1Producer->getSrc(1));
3305 _mls(T, Src1R, Src2R, Src0R);
3306 _mov(Dest, T);
3307 return;
3308 }
3309
John Portoccea7932015-11-17 04:58:36 -08003310 if (Srcs.hasConstOperand()) {
Eric Holke5727b82016-01-27 11:08:48 -08003311 assert(!isVectorType(DestTy));
John Portoccea7932015-11-17 04:58:36 -08003312 if (Srcs.immediateIsFlexEncodable()) {
John Porto614140e2015-11-23 11:43:13 -08003313 Variable *Src0R = Srcs.src0R(this);
John Portoccea7932015-11-17 04:58:36 -08003314 Operand *Src1RF = Srcs.src1RF(this);
3315 if (Srcs.swappedOperands()) {
3316 _rsb(T, Src0R, Src1RF);
3317 } else {
3318 _sub(T, Src0R, Src1RF);
3319 }
3320 _mov(Dest, T);
3321 return;
3322 }
3323 if (!Srcs.swappedOperands() && Srcs.negatedImmediateIsFlexEncodable()) {
John Porto614140e2015-11-23 11:43:13 -08003324 Variable *Src0R = Srcs.src0R(this);
John Portoccea7932015-11-17 04:58:36 -08003325 Operand *Src1F = Srcs.negatedSrc1F(this);
3326 _add(T, Src0R, Src1F);
3327 _mov(Dest, T);
3328 return;
3329 }
3330 }
3331 Variable *Src0R = Srcs.unswappedSrc0R(this);
3332 Variable *Src1R = Srcs.unswappedSrc1R(this);
Eric Holke5727b82016-01-27 11:08:48 -08003333 if (isVectorType(DestTy)) {
3334 _vsub(T, Src0R, Src1R);
3335 } else {
3336 _sub(T, Src0R, Src1R);
3337 }
Jan Voung70fa5252015-07-06 14:01:25 -07003338 _mov(Dest, T);
3339 return;
John Portoccea7932015-11-17 04:58:36 -08003340 }
Jan Voung70fa5252015-07-06 14:01:25 -07003341 case InstArithmetic::Mul: {
Jim Stichnoth386b52e2016-08-05 15:18:41 -07003342 const bool OptM1 = Func->getOptLevel() == Opt_m1;
John Porto98cc08c2015-11-24 12:30:01 -08003343 if (!OptM1 && Srcs.hasConstOperand()) {
3344 constexpr std::size_t MaxShifts = 4;
3345 std::array<StrengthReduction::AggregationElement, MaxShifts> Shifts;
3346 SizeT NumOperations;
3347 int32_t Const = Srcs.getConstantValue();
3348 const bool Invert = Const < 0;
3349 const bool MultiplyByZero = Const == 0;
3350 Operand *_0 =
3351 legalize(Ctx->getConstantZero(DestTy), Legal_Reg | Legal_Flex);
3352
3353 if (MultiplyByZero) {
3354 _mov(T, _0);
3355 _mov(Dest, T);
3356 return;
3357 }
3358
3359 if (Invert) {
3360 Const = -Const;
3361 }
3362
3363 if (StrengthReduction::tryToOptimize(Const, &NumOperations, &Shifts)) {
3364 assert(NumOperations >= 1);
3365 Variable *Src0R = Srcs.src0R(this);
3366 int32_t Start;
3367 int32_t End;
3368 if (NumOperations == 1 || Shifts[NumOperations - 1].shAmt() != 0) {
3369 // Multiplication by a power of 2 (NumOperations == 1); or
3370 // Multiplication by a even number not a power of 2.
3371 Start = 1;
3372 End = NumOperations;
3373 assert(Shifts[0].aggregateWithAdd());
3374 _lsl(T, Src0R, shAmtImm(Shifts[0].shAmt()));
3375 } else {
3376 // Multiplication by an odd number. Put the free barrel shifter to a
3377 // good use.
3378 Start = 0;
3379 End = NumOperations - 2;
3380 const StrengthReduction::AggregationElement &Last =
3381 Shifts[NumOperations - 1];
3382 const StrengthReduction::AggregationElement &SecondToLast =
3383 Shifts[NumOperations - 2];
3384 if (!Last.aggregateWithAdd()) {
3385 assert(SecondToLast.aggregateWithAdd());
3386 _rsb(T, Src0R, SecondToLast.createShiftedOperand(Func, Src0R));
3387 } else if (!SecondToLast.aggregateWithAdd()) {
3388 assert(Last.aggregateWithAdd());
3389 _sub(T, Src0R, SecondToLast.createShiftedOperand(Func, Src0R));
3390 } else {
3391 _add(T, Src0R, SecondToLast.createShiftedOperand(Func, Src0R));
3392 }
3393 }
3394
3395 // Odd numbers : S E I I
3396 // +---+---+---+---+---+---+ ... +---+---+---+---+
3397 // Shifts = | | | | | | | ... | | | | |
3398 // +---+---+---+---+---+---+ ... +---+---+---+---+
3399 // Even numbers: I S E
3400 //
3401 // S: Start; E: End; I: Init
3402 for (int32_t I = Start; I < End; ++I) {
3403 const StrengthReduction::AggregationElement &Current = Shifts[I];
3404 Operand *SrcF = Current.createShiftedOperand(Func, Src0R);
3405 if (Current.aggregateWithAdd()) {
3406 _add(T, T, SrcF);
3407 } else {
3408 _sub(T, T, SrcF);
3409 }
3410 }
3411
3412 if (Invert) {
3413 // T = 0 - T.
3414 _rsb(T, T, _0);
3415 }
3416
3417 _mov(Dest, T);
3418 return;
3419 }
3420 }
John Portoccea7932015-11-17 04:58:36 -08003421 Variable *Src0R = Srcs.unswappedSrc0R(this);
3422 Variable *Src1R = Srcs.unswappedSrc1R(this);
Eric Holk029bed92016-01-28 13:38:43 -08003423 if (isVectorType(DestTy)) {
3424 _vmul(T, Src0R, Src1R);
3425 } else {
3426 _mul(T, Src0R, Src1R);
3427 }
Jan Voung70fa5252015-07-06 14:01:25 -07003428 _mov(Dest, T);
3429 return;
3430 }
John Portoccea7932015-11-17 04:58:36 -08003431 case InstArithmetic::Shl: {
3432 Variable *Src0R = Srcs.unswappedSrc0R(this);
John Porto15e77d42016-04-13 12:57:14 -07003433 if (!isVectorType(T->getType())) {
Nicolas Capensfb705a62017-05-01 15:31:29 -04003434 if (Srcs.isSrc1ImmediateZero()) {
3435 _mov(T, Src0R);
3436 } else {
3437 Operand *Src1R = Srcs.unswappedSrc1RShAmtImm(this);
3438 _lsl(T, Src0R, Src1R);
3439 }
John Porto15e77d42016-04-13 12:57:14 -07003440 } else {
Nicolas Capens8d90a342017-09-27 14:33:11 -04003441 if (Srcs.hasConstOperand()) {
3442 ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
3443 _vshl(T, Src0R, ShAmt);
3444 } else {
3445 auto *Src1R = Srcs.unswappedSrc1R(this);
3446 _vshl(T, Src0R, Src1R)->setSignType(InstARM32::FS_Unsigned);
3447 }
John Porto15e77d42016-04-13 12:57:14 -07003448 }
Jan Voung70fa5252015-07-06 14:01:25 -07003449 _mov(Dest, T);
3450 return;
John Portoccea7932015-11-17 04:58:36 -08003451 }
3452 case InstArithmetic::Lshr: {
3453 Variable *Src0R = Srcs.unswappedSrc0R(this);
John Porto15e77d42016-04-13 12:57:14 -07003454 if (!isVectorType(T->getType())) {
John Porto15e77d42016-04-13 12:57:14 -07003455 if (DestTy != IceType_i32) {
3456 _uxt(Src0R, Src0R);
3457 }
Nicolas Capensfb705a62017-05-01 15:31:29 -04003458 if (Srcs.isSrc1ImmediateZero()) {
3459 _mov(T, Src0R);
3460 } else {
3461 Operand *Src1R = Srcs.unswappedSrc1RShAmtImm(this);
3462 _lsr(T, Src0R, Src1R);
3463 }
John Porto15e77d42016-04-13 12:57:14 -07003464 } else {
Nicolas Capens8d90a342017-09-27 14:33:11 -04003465 if (Srcs.hasConstOperand()) {
3466 ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
3467 _vshr(T, Src0R, ShAmt)->setSignType(InstARM32::FS_Unsigned);
3468 } else {
3469 auto *Src1R = Srcs.unswappedSrc1R(this);
3470 auto *Src1RNeg = makeReg(Src1R->getType());
3471 _vneg(Src1RNeg, Src1R);
3472 _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Unsigned);
3473 }
John Portoafc92af2015-10-16 10:34:04 -07003474 }
Jan Voung70fa5252015-07-06 14:01:25 -07003475 _mov(Dest, T);
3476 return;
John Portoccea7932015-11-17 04:58:36 -08003477 }
3478 case InstArithmetic::Ashr: {
3479 Variable *Src0R = Srcs.unswappedSrc0R(this);
John Porto15e77d42016-04-13 12:57:14 -07003480 if (!isVectorType(T->getType())) {
3481 if (DestTy != IceType_i32) {
3482 _sxt(Src0R, Src0R);
3483 }
Nicolas Capensfb705a62017-05-01 15:31:29 -04003484 if (Srcs.isSrc1ImmediateZero()) {
3485 _mov(T, Src0R);
3486 } else {
3487 _asr(T, Src0R, Srcs.unswappedSrc1RShAmtImm(this));
3488 }
John Porto15e77d42016-04-13 12:57:14 -07003489 } else {
Nicolas Capens8d90a342017-09-27 14:33:11 -04003490 if (Srcs.hasConstOperand()) {
3491 ConstantInteger32 *ShAmt = llvm::cast<ConstantInteger32>(Srcs.src1());
3492 _vshr(T, Src0R, ShAmt)->setSignType(InstARM32::FS_Signed);
3493 } else {
3494 auto *Src1R = Srcs.unswappedSrc1R(this);
3495 auto *Src1RNeg = makeReg(Src1R->getType());
3496 _vneg(Src1RNeg, Src1R);
3497 _vshl(T, Src0R, Src1RNeg)->setSignType(InstARM32::FS_Signed);
3498 }
John Portoafc92af2015-10-16 10:34:04 -07003499 }
Jan Voung70fa5252015-07-06 14:01:25 -07003500 _mov(Dest, T);
3501 return;
John Portoccea7932015-11-17 04:58:36 -08003502 }
Jan Voung70fa5252015-07-06 14:01:25 -07003503 case InstArithmetic::Udiv:
3504 case InstArithmetic::Sdiv:
3505 case InstArithmetic::Urem:
3506 case InstArithmetic::Srem:
John Portoccea7932015-11-17 04:58:36 -08003507 llvm::report_fatal_error(
3508 "Integer div/rem should have been handled earlier.");
Jan Voung70fa5252015-07-06 14:01:25 -07003509 return;
3510 case InstArithmetic::Fadd:
Jan Voung70fa5252015-07-06 14:01:25 -07003511 case InstArithmetic::Fsub:
Jan Voung70fa5252015-07-06 14:01:25 -07003512 case InstArithmetic::Fmul:
Jan Voung70fa5252015-07-06 14:01:25 -07003513 case InstArithmetic::Fdiv:
Jan Voung70fa5252015-07-06 14:01:25 -07003514 case InstArithmetic::Frem:
John Portoccea7932015-11-17 04:58:36 -08003515 llvm::report_fatal_error(
3516 "Floating point arith should have been handled earlier.");
Jan Voung70fa5252015-07-06 14:01:25 -07003517 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07003518 }
3519}
3520
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08003521void TargetARM32::lowerAssign(const InstAssign *Instr) {
3522 Variable *Dest = Instr->getDest();
John Porto614140e2015-11-23 11:43:13 -08003523
3524 if (Dest->isRematerializable()) {
John Porto1d937a82015-12-17 06:19:34 -08003525 Context.insert<InstFakeDef>(Dest);
John Porto614140e2015-11-23 11:43:13 -08003526 return;
3527 }
3528
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08003529 Operand *Src0 = Instr->getSrc(0);
Jan Voungb3401d22015-05-18 09:38:21 -07003530 assert(Dest->getType() == Src0->getType());
3531 if (Dest->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07003532 Src0 = legalizeUndef(Src0);
John Porto578f1162015-10-06 06:54:42 -07003533
John Portoccea7932015-11-17 04:58:36 -08003534 Variable *T_Lo = makeReg(IceType_i32);
3535 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3536 Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg | Legal_Flex);
Jan Voungb3401d22015-05-18 09:38:21 -07003537 _mov(T_Lo, Src0Lo);
3538 _mov(DestLo, T_Lo);
John Portoccea7932015-11-17 04:58:36 -08003539
3540 Variable *T_Hi = makeReg(IceType_i32);
3541 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
3542 Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex);
Jan Voungb3401d22015-05-18 09:38:21 -07003543 _mov(T_Hi, Src0Hi);
3544 _mov(DestHi, T_Hi);
John Portoccea7932015-11-17 04:58:36 -08003545
3546 return;
Jan Voungb3401d22015-05-18 09:38:21 -07003547 }
John Portoccea7932015-11-17 04:58:36 -08003548
3549 Operand *NewSrc;
3550 if (Dest->hasReg()) {
3551 // If Dest already has a physical register, then legalize the Src operand
3552 // into a Variable with the same register assignment. This especially
3553 // helps allow the use of Flex operands.
3554 NewSrc = legalize(Src0, Legal_Reg | Legal_Flex, Dest->getRegNum());
3555 } else {
3556 // Dest could be a stack operand. Since we could potentially need to do a
3557 // Store (and store can only have Register operands), legalize this to a
3558 // register.
3559 NewSrc = legalize(Src0, Legal_Reg);
3560 }
3561
3562 if (isVectorType(Dest->getType()) || isScalarFloatingType(Dest->getType())) {
3563 NewSrc = legalize(NewSrc, Legal_Reg | Legal_Mem);
3564 }
3565 _mov(Dest, NewSrc);
Jan Voungb36ad9b2015-04-21 17:01:49 -07003566}
3567
John Porto7b3d9cb2015-11-11 14:26:57 -08003568TargetARM32::ShortCircuitCondAndLabel TargetARM32::lowerInt1ForBranch(
3569 Operand *Boolean, const LowerInt1BranchTarget &TargetTrue,
3570 const LowerInt1BranchTarget &TargetFalse, uint32_t ShortCircuitable) {
3571 InstARM32Label *NewShortCircuitLabel = nullptr;
3572 Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
3573
John Portoeb13acc2015-12-09 05:10:58 -08003574 const Inst *Producer = Computations.getProducerOf(Boolean);
John Porto7b3d9cb2015-11-11 14:26:57 -08003575
3576 if (Producer == nullptr) {
3577 // No producer, no problem: just do emit code to perform (Boolean & 1) and
3578 // set the flags register. The branch should be taken if the resulting flags
3579 // indicate a non-zero result.
3580 _tst(legalizeToReg(Boolean), _1);
3581 return ShortCircuitCondAndLabel(CondWhenTrue(CondARM32::NE));
3582 }
3583
3584 switch (Producer->getKind()) {
3585 default:
John Portoc39ec102015-12-01 13:00:43 -08003586 llvm::report_fatal_error("Unexpected producer.");
John Porto7b3d9cb2015-11-11 14:26:57 -08003587 case Inst::Icmp: {
3588 return ShortCircuitCondAndLabel(
3589 lowerIcmpCond(llvm::cast<InstIcmp>(Producer)));
3590 } break;
3591 case Inst::Fcmp: {
3592 return ShortCircuitCondAndLabel(
3593 lowerFcmpCond(llvm::cast<InstFcmp>(Producer)));
3594 } break;
3595 case Inst::Cast: {
3596 const auto *CastProducer = llvm::cast<InstCast>(Producer);
3597 assert(CastProducer->getCastKind() == InstCast::Trunc);
3598 Operand *Src = CastProducer->getSrc(0);
3599 if (Src->getType() == IceType_i64)
3600 Src = loOperand(Src);
3601 _tst(legalizeToReg(Src), _1);
3602 return ShortCircuitCondAndLabel(CondWhenTrue(CondARM32::NE));
3603 } break;
3604 case Inst::Arithmetic: {
3605 const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
3606 switch (ArithProducer->getOp()) {
3607 default:
John Portoc39ec102015-12-01 13:00:43 -08003608 llvm::report_fatal_error("Unhandled Arithmetic Producer.");
John Porto7b3d9cb2015-11-11 14:26:57 -08003609 case InstArithmetic::And: {
3610 if (!(ShortCircuitable & SC_And)) {
3611 NewShortCircuitLabel = InstARM32Label::create(Func, this);
3612 }
3613
3614 LowerInt1BranchTarget NewTarget =
3615 TargetFalse.createForLabelOrDuplicate(NewShortCircuitLabel);
3616
3617 ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
3618 Producer->getSrc(0), TargetTrue, NewTarget, SC_And);
3619 const CondWhenTrue &Cond = CondAndLabel.Cond;
3620
3621 _br_short_circuit(NewTarget, Cond.invert());
3622
3623 InstARM32Label *const ShortCircuitLabel = CondAndLabel.ShortCircuitTarget;
3624 if (ShortCircuitLabel != nullptr)
3625 Context.insert(ShortCircuitLabel);
3626
3627 return ShortCircuitCondAndLabel(
3628 lowerInt1ForBranch(Producer->getSrc(1), TargetTrue, NewTarget, SC_All)
3629 .assertNoLabelAndReturnCond(),
3630 NewShortCircuitLabel);
3631 } break;
3632 case InstArithmetic::Or: {
3633 if (!(ShortCircuitable & SC_Or)) {
3634 NewShortCircuitLabel = InstARM32Label::create(Func, this);
3635 }
3636
3637 LowerInt1BranchTarget NewTarget =
3638 TargetTrue.createForLabelOrDuplicate(NewShortCircuitLabel);
3639
3640 ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
3641 Producer->getSrc(0), NewTarget, TargetFalse, SC_Or);
3642 const CondWhenTrue &Cond = CondAndLabel.Cond;
3643
3644 _br_short_circuit(NewTarget, Cond);
3645
3646 InstARM32Label *const ShortCircuitLabel = CondAndLabel.ShortCircuitTarget;
3647 if (ShortCircuitLabel != nullptr)
3648 Context.insert(ShortCircuitLabel);
3649
3650 return ShortCircuitCondAndLabel(lowerInt1ForBranch(Producer->getSrc(1),
3651 NewTarget, TargetFalse,
3652 SC_All)
3653 .assertNoLabelAndReturnCond(),
3654 NewShortCircuitLabel);
3655 } break;
3656 }
3657 }
3658 }
3659}
3660
John Porto4a5e6d02015-11-04 09:32:55 -08003661void TargetARM32::lowerBr(const InstBr *Instr) {
3662 if (Instr->isUnconditional()) {
3663 _br(Instr->getTargetUnconditional());
Jan Voung3bfd99a2015-05-22 16:35:25 -07003664 return;
3665 }
Jan Voung3bfd99a2015-05-22 16:35:25 -07003666
John Porto7b3d9cb2015-11-11 14:26:57 -08003667 CfgNode *TargetTrue = Instr->getTargetTrue();
3668 CfgNode *TargetFalse = Instr->getTargetFalse();
3669 ShortCircuitCondAndLabel CondAndLabel = lowerInt1ForBranch(
3670 Instr->getCondition(), LowerInt1BranchTarget(TargetTrue),
3671 LowerInt1BranchTarget(TargetFalse), SC_All);
3672 assert(CondAndLabel.ShortCircuitTarget == nullptr);
3673
3674 const CondWhenTrue &Cond = CondAndLabel.Cond;
3675 if (Cond.WhenTrue1 != CondARM32::kNone) {
3676 assert(Cond.WhenTrue0 != CondARM32::AL);
3677 _br(TargetTrue, Cond.WhenTrue1);
John Porto4a5e6d02015-11-04 09:32:55 -08003678 }
3679
John Porto7b3d9cb2015-11-11 14:26:57 -08003680 switch (Cond.WhenTrue0) {
3681 default:
3682 _br(TargetTrue, TargetFalse, Cond.WhenTrue0);
3683 break;
3684 case CondARM32::kNone:
3685 _br(TargetFalse);
3686 break;
3687 case CondARM32::AL:
3688 _br(TargetTrue);
3689 break;
John Porto4a5e6d02015-11-04 09:32:55 -08003690 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07003691}
3692
Jan Voung3bfd99a2015-05-22 16:35:25 -07003693void TargetARM32::lowerCall(const InstCall *Instr) {
John Portob82d79a2016-03-01 06:11:05 -08003694 Operand *CallTarget = Instr->getCallTarget();
John Portoc39ec102015-12-01 13:00:43 -08003695 if (Instr->isTargetHelperCall()) {
3696 auto TargetHelperPreamble = ARM32HelpersPreamble.find(CallTarget);
3697 if (TargetHelperPreamble != ARM32HelpersPreamble.end()) {
3698 (this->*TargetHelperPreamble->second)(Instr);
3699 }
3700 }
Jan Voung0fa6c5a2015-06-01 11:04:04 -07003701 MaybeLeafFunc = false;
Jan Voungb0a8c242015-06-18 15:00:14 -07003702 NeedsStackAlignment = true;
Jan Voung0fa6c5a2015-06-01 11:04:04 -07003703
Jan Voungb0a8c242015-06-18 15:00:14 -07003704 // Assign arguments to registers and stack. Also reserve stack.
3705 TargetARM32::CallingConv CC;
3706 // Pair of Arg Operand -> GPR number assignments.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08003707 llvm::SmallVector<std::pair<Operand *, RegNumT>, NumGPRArgs> GPRArgs;
3708 llvm::SmallVector<std::pair<Operand *, RegNumT>, NumFP32Args> FPArgs;
Jan Voungb0a8c242015-06-18 15:00:14 -07003709 // Pair of Arg Operand -> stack offset.
3710 llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs;
John Portof4198542015-11-20 14:17:23 -08003711 size_t ParameterAreaSizeBytes = 0;
Jan Voungb0a8c242015-06-18 15:00:14 -07003712
3713 // Classify each argument operand according to the location where the
3714 // argument is passed.
3715 for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) {
Jan Voungfbdd2442015-07-15 12:36:20 -07003716 Operand *Arg = legalizeUndef(Instr->getArg(i));
John Porto2187c842015-12-16 07:48:25 -08003717 const Type Ty = Arg->getType();
3718 bool InReg = false;
Jim Stichnoth8aa39662016-02-10 11:20:30 -08003719 RegNumT Reg;
John Porto2187c842015-12-16 07:48:25 -08003720 if (isScalarIntegerType(Ty)) {
3721 InReg = CC.argInGPR(Ty, &Reg);
Jan Voungb0a8c242015-06-18 15:00:14 -07003722 } else {
John Porto2187c842015-12-16 07:48:25 -08003723 InReg = CC.argInVFP(Ty, &Reg);
Jan Voungb0a8c242015-06-18 15:00:14 -07003724 }
3725
John Porto2187c842015-12-16 07:48:25 -08003726 if (!InReg) {
Jan Voungb0a8c242015-06-18 15:00:14 -07003727 ParameterAreaSizeBytes =
3728 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty);
3729 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes));
John Portoba6a67c2015-09-25 15:19:45 -07003730 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty);
John Porto2187c842015-12-16 07:48:25 -08003731 continue;
3732 }
3733
3734 if (Ty == IceType_i64) {
3735 Operand *Lo = loOperand(Arg);
3736 Operand *Hi = hiOperand(Arg);
Jim Stichnoth8aa39662016-02-10 11:20:30 -08003737 GPRArgs.push_back(std::make_pair(
3738 Lo, RegNumT::fixme(RegARM32::getI64PairFirstGPRNum(Reg))));
3739 GPRArgs.push_back(std::make_pair(
3740 Hi, RegNumT::fixme(RegARM32::getI64PairSecondGPRNum(Reg))));
John Porto2187c842015-12-16 07:48:25 -08003741 } else if (isScalarIntegerType(Ty)) {
3742 GPRArgs.push_back(std::make_pair(Arg, Reg));
3743 } else {
3744 FPArgs.push_back(std::make_pair(Arg, Reg));
Jan Voungb0a8c242015-06-18 15:00:14 -07003745 }
3746 }
3747
Andrew Scull57e12682015-09-16 11:30:19 -07003748 // Adjust the parameter area so that the stack is aligned. It is assumed that
3749 // the stack is already aligned at the start of the calling sequence.
Jan Voungb0a8c242015-06-18 15:00:14 -07003750 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes);
3751
John Portof4198542015-11-20 14:17:23 -08003752 if (ParameterAreaSizeBytes > MaxOutArgsSizeBytes) {
3753 llvm::report_fatal_error("MaxOutArgsSizeBytes is not really a max.");
Jan Voungb0a8c242015-06-18 15:00:14 -07003754 }
3755
Andrew Scull57e12682015-09-16 11:30:19 -07003756 // Copy arguments that are passed on the stack to the appropriate stack
3757 // locations.
Jan Voungf645d852015-07-09 10:35:09 -07003758 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
Jan Voungb0a8c242015-06-18 15:00:14 -07003759 for (auto &StackArg : StackArgs) {
3760 ConstantInteger32 *Loc =
3761 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second));
3762 Type Ty = StackArg.first->getType();
3763 OperandARM32Mem *Addr;
3764 constexpr bool SignExt = false;
3765 if (OperandARM32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) {
3766 Addr = OperandARM32Mem::create(Func, Ty, SP, Loc);
3767 } else {
3768 Variable *NewBase = Func->makeVariable(SP->getType());
3769 lowerArithmetic(
3770 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc));
3771 Addr = formMemoryOperand(NewBase, Ty);
3772 }
3773 lowerStore(InstStore::create(Func, StackArg.first, Addr));
3774 }
3775
Andrew Scull57e12682015-09-16 11:30:19 -07003776 // Generate the call instruction. Assign its result to a temporary with high
3777 // register allocation weight.
Jan Voung3bfd99a2015-05-22 16:35:25 -07003778 Variable *Dest = Instr->getDest();
3779 // ReturnReg doubles as ReturnRegLo as necessary.
3780 Variable *ReturnReg = nullptr;
3781 Variable *ReturnRegHi = nullptr;
3782 if (Dest) {
3783 switch (Dest->getType()) {
3784 case IceType_NUM:
John Portoc39ec102015-12-01 13:00:43 -08003785 llvm::report_fatal_error("Invalid Call dest type");
Jan Voung3bfd99a2015-05-22 16:35:25 -07003786 break;
3787 case IceType_void:
3788 break;
3789 case IceType_i1:
John Portoeb13acc2015-12-09 05:10:58 -08003790 assert(Computations.getProducerOf(Dest) == nullptr);
John Porto7b3d9cb2015-11-11 14:26:57 -08003791 // Fall-through intended.
Jan Voung3bfd99a2015-05-22 16:35:25 -07003792 case IceType_i8:
3793 case IceType_i16:
3794 case IceType_i32:
3795 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_r0);
3796 break;
3797 case IceType_i64:
3798 ReturnReg = makeReg(IceType_i32, RegARM32::Reg_r0);
3799 ReturnRegHi = makeReg(IceType_i32, RegARM32::Reg_r1);
3800 break;
3801 case IceType_f32:
Jan Voung86ebec12015-08-09 07:58:35 -07003802 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_s0);
3803 break;
Jan Voung3bfd99a2015-05-22 16:35:25 -07003804 case IceType_f64:
Jan Voung86ebec12015-08-09 07:58:35 -07003805 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_d0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003806 break;
3807 case IceType_v4i1:
3808 case IceType_v8i1:
3809 case IceType_v16i1:
3810 case IceType_v16i8:
3811 case IceType_v8i16:
3812 case IceType_v4i32:
3813 case IceType_v4f32:
Jan Voung86ebec12015-08-09 07:58:35 -07003814 ReturnReg = makeReg(Dest->getType(), RegARM32::Reg_q0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003815 break;
3816 }
3817 }
Jan Voungb0a8c242015-06-18 15:00:14 -07003818
John Portob82d79a2016-03-01 06:11:05 -08003819 // Allow ConstantRelocatable to be left alone as a direct call, but force
3820 // other constants like ConstantInteger32 to be in a register and make it an
3821 // indirect call.
3822 if (!llvm::isa<ConstantRelocatable>(CallTarget)) {
3823 CallTarget = legalize(CallTarget, Legal_Reg);
3824 }
John Portoba6a67c2015-09-25 15:19:45 -07003825
3826 // Copy arguments to be passed in registers to the appropriate registers.
John Portodc619252016-02-10 15:57:16 -08003827 CfgVector<Variable *> RegArgs;
John Portoba6a67c2015-09-25 15:19:45 -07003828 for (auto &FPArg : FPArgs) {
John Portodc619252016-02-10 15:57:16 -08003829 RegArgs.emplace_back(legalizeToReg(FPArg.first, FPArg.second));
John Portoba6a67c2015-09-25 15:19:45 -07003830 }
3831 for (auto &GPRArg : GPRArgs) {
John Portodc619252016-02-10 15:57:16 -08003832 RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second));
3833 }
3834
3835 // Generate a FakeUse of register arguments so that they do not get dead code
3836 // eliminated as a result of the FakeKill of scratch registers after the call.
3837 // These fake-uses need to be placed here to avoid argument registers from
3838 // being used during the legalizeToReg() calls above.
3839 for (auto *RegArg : RegArgs) {
3840 Context.insert<InstFakeUse>(RegArg);
John Portoba6a67c2015-09-25 15:19:45 -07003841 }
John Porto52b51572015-12-05 14:16:25 -08003842
3843 InstARM32Call *NewCall =
3844 Sandboxer(this, InstBundleLock::Opt_AlignToEnd).bl(ReturnReg, CallTarget);
3845
Jan Voung3bfd99a2015-05-22 16:35:25 -07003846 if (ReturnRegHi)
John Porto1d937a82015-12-17 06:19:34 -08003847 Context.insert<InstFakeDef>(ReturnRegHi);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003848
3849 // Insert a register-kill pseudo instruction.
John Porto1d937a82015-12-17 06:19:34 -08003850 Context.insert<InstFakeKill>(NewCall);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003851
3852 // Generate a FakeUse to keep the call live if necessary.
3853 if (Instr->hasSideEffects() && ReturnReg) {
John Porto1d937a82015-12-17 06:19:34 -08003854 Context.insert<InstFakeUse>(ReturnReg);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003855 }
3856
John Portoc39ec102015-12-01 13:00:43 -08003857 if (Dest != nullptr) {
3858 // Assign the result of the call to Dest.
3859 if (ReturnReg != nullptr) {
3860 if (ReturnRegHi) {
3861 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest);
3862 Variable *DestLo = Dest64On32->getLo();
3863 Variable *DestHi = Dest64On32->getHi();
3864 _mov(DestLo, ReturnReg);
3865 _mov(DestHi, ReturnRegHi);
Jan Voung3bfd99a2015-05-22 16:35:25 -07003866 } else {
John Portoc39ec102015-12-01 13:00:43 -08003867 if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) {
3868 _mov(Dest, ReturnReg);
3869 } else {
3870 assert(isIntegerType(Dest->getType()) &&
3871 typeWidthInBytes(Dest->getType()) <= 4);
3872 _mov(Dest, ReturnReg);
3873 }
Jan Voung3bfd99a2015-05-22 16:35:25 -07003874 }
3875 }
3876 }
John Portoc39ec102015-12-01 13:00:43 -08003877
3878 if (Instr->isTargetHelperCall()) {
John Portob82d79a2016-03-01 06:11:05 -08003879 auto TargetHelpersPostamble = ARM32HelpersPostamble.find(CallTarget);
John Portoc39ec102015-12-01 13:00:43 -08003880 if (TargetHelpersPostamble != ARM32HelpersPostamble.end()) {
3881 (this->*TargetHelpersPostamble->second)(Instr);
3882 }
3883 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07003884}
3885
John Portoba6a67c2015-09-25 15:19:45 -07003886namespace {
John Portoe0b829f2015-09-28 09:50:48 -07003887void configureBitcastTemporary(Variable64On32 *Var) {
3888 Var->setMustNotHaveReg();
John Portoba6a67c2015-09-25 15:19:45 -07003889 Var->getHi()->setMustHaveReg();
3890 Var->getLo()->setMustHaveReg();
3891}
3892} // end of anonymous namespace
3893
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08003894void TargetARM32::lowerCast(const InstCast *Instr) {
3895 InstCast::OpKind CastKind = Instr->getCastKind();
3896 Variable *Dest = Instr->getDest();
John Portoe88c7de2016-04-14 11:51:38 -07003897 const Type DestTy = Dest->getType();
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08003898 Operand *Src0 = legalizeUndef(Instr->getSrc(0));
Jan Voungb36ad9b2015-04-21 17:01:49 -07003899 switch (CastKind) {
3900 default:
3901 Func->setError("Cast type not supported");
3902 return;
3903 case InstCast::Sext: {
John Portoe88c7de2016-04-14 11:51:38 -07003904 if (isVectorType(DestTy)) {
3905 Variable *T0 = makeReg(DestTy);
3906 Variable *T1 = makeReg(DestTy);
3907 ConstantInteger32 *ShAmt = nullptr;
3908 switch (DestTy) {
3909 default:
3910 llvm::report_fatal_error("Unexpected type in vector sext.");
3911 case IceType_v16i8:
3912 ShAmt = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(7));
3913 break;
3914 case IceType_v8i16:
3915 ShAmt = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(15));
3916 break;
3917 case IceType_v4i32:
3918 ShAmt = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(31));
3919 break;
3920 }
3921 auto *Src0R = legalizeToReg(Src0);
3922 _vshl(T0, Src0R, ShAmt);
3923 _vshr(T1, T0, ShAmt)->setSignType(InstARM32::FS_Signed);
3924 _mov(Dest, T1);
3925 } else if (DestTy == IceType_i64) {
Jan Voung66c3d5e2015-06-04 17:02:31 -07003926 // t1=sxtb src; t2= mov t1 asr #31; dst.lo=t1; dst.hi=t2
3927 Constant *ShiftAmt = Ctx->getConstantInt32(31);
Jim Stichnoth54f3d512015-12-11 09:53:00 -08003928 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3929 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Jan Voung66c3d5e2015-06-04 17:02:31 -07003930 Variable *T_Lo = makeReg(DestLo->getType());
3931 if (Src0->getType() == IceType_i32) {
3932 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
3933 _mov(T_Lo, Src0RF);
John Porto4a5e6d02015-11-04 09:32:55 -08003934 } else if (Src0->getType() != IceType_i1) {
Andrew Scull97f460d2015-07-21 10:07:42 -07003935 Variable *Src0R = legalizeToReg(Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07003936 _sxt(T_Lo, Src0R);
John Porto4a5e6d02015-11-04 09:32:55 -08003937 } else {
John Porto7b3d9cb2015-11-11 14:26:57 -08003938 Operand *_0 = Ctx->getConstantZero(IceType_i32);
3939 Operand *_m1 = Ctx->getConstantInt32(-1);
3940 lowerInt1ForSelect(T_Lo, Src0, _m1, _0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07003941 }
3942 _mov(DestLo, T_Lo);
3943 Variable *T_Hi = makeReg(DestHi->getType());
3944 if (Src0->getType() != IceType_i1) {
3945 _mov(T_Hi, OperandARM32FlexReg::create(Func, IceType_i32, T_Lo,
3946 OperandARM32::ASR, ShiftAmt));
3947 } else {
3948 // For i1, the asr instruction is already done above.
3949 _mov(T_Hi, T_Lo);
3950 }
3951 _mov(DestHi, T_Hi);
John Porto4a5e6d02015-11-04 09:32:55 -08003952 } else if (Src0->getType() != IceType_i1) {
Jan Voung66c3d5e2015-06-04 17:02:31 -07003953 // t1 = sxt src; dst = t1
Andrew Scull97f460d2015-07-21 10:07:42 -07003954 Variable *Src0R = legalizeToReg(Src0);
John Portoe88c7de2016-04-14 11:51:38 -07003955 Variable *T = makeReg(DestTy);
Jan Voung66c3d5e2015-06-04 17:02:31 -07003956 _sxt(T, Src0R);
3957 _mov(Dest, T);
John Porto4a5e6d02015-11-04 09:32:55 -08003958 } else {
John Porto7b3d9cb2015-11-11 14:26:57 -08003959 Constant *_0 = Ctx->getConstantZero(IceType_i32);
John Portoe88c7de2016-04-14 11:51:38 -07003960 Operand *_m1 = Ctx->getConstantInt(DestTy, -1);
3961 Variable *T = makeReg(DestTy);
John Porto7b3d9cb2015-11-11 14:26:57 -08003962 lowerInt1ForSelect(T, Src0, _m1, _0);
John Porto4a5e6d02015-11-04 09:32:55 -08003963 _mov(Dest, T);
Jan Voung66c3d5e2015-06-04 17:02:31 -07003964 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07003965 break;
3966 }
3967 case InstCast::Zext: {
John Portoe88c7de2016-04-14 11:51:38 -07003968 if (isVectorType(DestTy)) {
3969 auto *Mask = makeReg(DestTy);
3970 auto *_1 = Ctx->getConstantInt32(1);
3971 auto *T = makeReg(DestTy);
3972 auto *Src0R = legalizeToReg(Src0);
3973 _mov(Mask, _1);
3974 _vand(T, Src0R, Mask);
3975 _mov(Dest, T);
3976 } else if (DestTy == IceType_i64) {
Jan Voung66c3d5e2015-06-04 17:02:31 -07003977 // t1=uxtb src; dst.lo=t1; dst.hi=0
John Porto7b3d9cb2015-11-11 14:26:57 -08003978 Operand *_0 =
3979 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
Jim Stichnoth54f3d512015-12-11 09:53:00 -08003980 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
3981 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Jan Voung66c3d5e2015-06-04 17:02:31 -07003982 Variable *T_Lo = makeReg(DestLo->getType());
John Porto4a5e6d02015-11-04 09:32:55 -08003983
John Porto7b3d9cb2015-11-11 14:26:57 -08003984 switch (Src0->getType()) {
3985 default: {
3986 assert(Src0->getType() != IceType_i64);
3987 _uxt(T_Lo, legalizeToReg(Src0));
3988 } break;
3989 case IceType_i32: {
3990 _mov(T_Lo, legalize(Src0, Legal_Reg | Legal_Flex));
3991 } break;
3992 case IceType_i1: {
3993 SafeBoolChain Safe = lowerInt1(T_Lo, Src0);
3994 if (Safe == SBC_No) {
3995 Operand *_1 =
3996 legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
3997 _and(T_Lo, T_Lo, _1);
3998 }
3999 } break;
John Porto4a5e6d02015-11-04 09:32:55 -08004000 }
4001
Jan Voung66c3d5e2015-06-04 17:02:31 -07004002 _mov(DestLo, T_Lo);
John Porto7b3d9cb2015-11-11 14:26:57 -08004003
Jan Voung66c3d5e2015-06-04 17:02:31 -07004004 Variable *T_Hi = makeReg(DestLo->getType());
John Porto4a5e6d02015-11-04 09:32:55 -08004005 _mov(T_Hi, _0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07004006 _mov(DestHi, T_Hi);
4007 } else if (Src0->getType() == IceType_i1) {
John Portoe88c7de2016-04-14 11:51:38 -07004008 Variable *T = makeReg(DestTy);
John Porto4a5e6d02015-11-04 09:32:55 -08004009
John Porto7b3d9cb2015-11-11 14:26:57 -08004010 SafeBoolChain Safe = lowerInt1(T, Src0);
4011 if (Safe == SBC_No) {
4012 Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
4013 _and(T, T, _1);
John Porto4a5e6d02015-11-04 09:32:55 -08004014 }
4015
Jan Voung66c3d5e2015-06-04 17:02:31 -07004016 _mov(Dest, T);
4017 } else {
4018 // t1 = uxt src; dst = t1
Andrew Scull97f460d2015-07-21 10:07:42 -07004019 Variable *Src0R = legalizeToReg(Src0);
John Portoe88c7de2016-04-14 11:51:38 -07004020 Variable *T = makeReg(DestTy);
Jan Voung66c3d5e2015-06-04 17:02:31 -07004021 _uxt(T, Src0R);
4022 _mov(Dest, T);
4023 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07004024 break;
4025 }
4026 case InstCast::Trunc: {
John Portoe88c7de2016-04-14 11:51:38 -07004027 if (isVectorType(DestTy)) {
4028 auto *T = makeReg(DestTy);
4029 auto *Src0R = legalizeToReg(Src0);
4030 _mov(T, Src0R);
4031 _mov(Dest, T);
Jan Voung66c3d5e2015-06-04 17:02:31 -07004032 } else {
Jan Voung66c3d5e2015-06-04 17:02:31 -07004033 if (Src0->getType() == IceType_i64)
4034 Src0 = loOperand(Src0);
4035 Operand *Src0RF = legalize(Src0, Legal_Reg | Legal_Flex);
4036 // t1 = trunc Src0RF; Dest = t1
John Portoe88c7de2016-04-14 11:51:38 -07004037 Variable *T = makeReg(DestTy);
Jan Voung66c3d5e2015-06-04 17:02:31 -07004038 _mov(T, Src0RF);
John Portoe88c7de2016-04-14 11:51:38 -07004039 if (DestTy == IceType_i1)
Jan Voung66c3d5e2015-06-04 17:02:31 -07004040 _and(T, T, Ctx->getConstantInt1(1));
4041 _mov(Dest, T);
4042 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07004043 break;
4044 }
4045 case InstCast::Fptrunc:
Jan Voungb36ad9b2015-04-21 17:01:49 -07004046 case InstCast::Fpext: {
John Portoc31e2ed2015-09-11 05:17:08 -07004047 // fptrunc: dest.f32 = fptrunc src0.fp64
4048 // fpext: dest.f64 = fptrunc src0.fp32
4049 const bool IsTrunc = CastKind == InstCast::Fptrunc;
John Portoe88c7de2016-04-14 11:51:38 -07004050 assert(!isVectorType(DestTy));
4051 assert(DestTy == (IsTrunc ? IceType_f32 : IceType_f64));
John Portoc31e2ed2015-09-11 05:17:08 -07004052 assert(Src0->getType() == (IsTrunc ? IceType_f64 : IceType_f32));
4053 Variable *Src0R = legalizeToReg(Src0);
John Portoe88c7de2016-04-14 11:51:38 -07004054 Variable *T = makeReg(DestTy);
John Portoc31e2ed2015-09-11 05:17:08 -07004055 _vcvt(T, Src0R, IsTrunc ? InstARM32Vcvt::D2s : InstARM32Vcvt::S2d);
4056 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07004057 break;
4058 }
4059 case InstCast::Fptosi:
John Portoc31e2ed2015-09-11 05:17:08 -07004060 case InstCast::Fptoui: {
John Portoe88c7de2016-04-14 11:51:38 -07004061 const bool DestIsSigned = CastKind == InstCast::Fptosi;
4062 Variable *Src0R = legalizeToReg(Src0);
4063
4064 if (isVectorType(DestTy)) {
4065 assert(typeElementType(Src0->getType()) == IceType_f32);
4066 auto *T = makeReg(DestTy);
4067 _vcvt(T, Src0R,
4068 DestIsSigned ? InstARM32Vcvt::Vs2si : InstARM32Vcvt::Vs2ui);
4069 _mov(Dest, T);
John Portoba6a67c2015-09-25 15:19:45 -07004070 break;
4071 }
4072
John Portoba6a67c2015-09-25 15:19:45 -07004073 const bool Src0IsF32 = isFloat32Asserting32Or64(Src0->getType());
4074 if (llvm::isa<Variable64On32>(Dest)) {
John Portoc39ec102015-12-01 13:00:43 -08004075 llvm::report_fatal_error("fp-to-i64 should have been pre-lowered.");
John Portoba6a67c2015-09-25 15:19:45 -07004076 }
John Portoc31e2ed2015-09-11 05:17:08 -07004077 // fptosi:
4078 // t1.fp = vcvt src0.fp
4079 // t2.i32 = vmov t1.fp
4080 // dest.int = conv t2.i32 @ Truncates the result if needed.
4081 // fptoui:
4082 // t1.fp = vcvt src0.fp
4083 // t2.u32 = vmov t1.fp
4084 // dest.uint = conv t2.u32 @ Truncates the result if needed.
John Portoc31e2ed2015-09-11 05:17:08 -07004085 Variable *T_fp = makeReg(IceType_f32);
John Portoba6a67c2015-09-25 15:19:45 -07004086 const InstARM32Vcvt::VcvtVariant Conversion =
4087 Src0IsF32 ? (DestIsSigned ? InstARM32Vcvt::S2si : InstARM32Vcvt::S2ui)
4088 : (DestIsSigned ? InstARM32Vcvt::D2si : InstARM32Vcvt::D2ui);
4089 _vcvt(T_fp, Src0R, Conversion);
John Portoc31e2ed2015-09-11 05:17:08 -07004090 Variable *T = makeReg(IceType_i32);
John Portoba6a67c2015-09-25 15:19:45 -07004091 _mov(T, T_fp);
John Portoe88c7de2016-04-14 11:51:38 -07004092 if (DestTy != IceType_i32) {
4093 Variable *T_1 = makeReg(DestTy);
John Portoc31e2ed2015-09-11 05:17:08 -07004094 lowerCast(InstCast::create(Func, InstCast::Trunc, T_1, T));
4095 T = T_1;
4096 }
4097 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07004098 break;
John Portoc31e2ed2015-09-11 05:17:08 -07004099 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07004100 case InstCast::Sitofp:
Jan Voungb36ad9b2015-04-21 17:01:49 -07004101 case InstCast::Uitofp: {
John Portoe88c7de2016-04-14 11:51:38 -07004102 const bool SourceIsSigned = CastKind == InstCast::Sitofp;
4103
4104 if (isVectorType(DestTy)) {
4105 assert(typeElementType(DestTy) == IceType_f32);
4106 auto *T = makeReg(DestTy);
4107 Variable *Src0R = legalizeToReg(Src0);
4108 _vcvt(T, Src0R,
4109 SourceIsSigned ? InstARM32Vcvt::Vsi2s : InstARM32Vcvt::Vui2s);
4110 _mov(Dest, T);
John Portoba6a67c2015-09-25 15:19:45 -07004111 break;
4112 }
John Portoe88c7de2016-04-14 11:51:38 -07004113
4114 const bool DestIsF32 = isFloat32Asserting32Or64(DestTy);
John Portoba6a67c2015-09-25 15:19:45 -07004115 if (Src0->getType() == IceType_i64) {
John Portoc39ec102015-12-01 13:00:43 -08004116 llvm::report_fatal_error("i64-to-fp should have been pre-lowered.");
John Portoba6a67c2015-09-25 15:19:45 -07004117 }
John Portoc31e2ed2015-09-11 05:17:08 -07004118 // sitofp:
4119 // t1.i32 = sext src.int @ sign-extends src0 if needed.
4120 // t2.fp32 = vmov t1.i32
4121 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
4122 // uitofp:
4123 // t1.i32 = zext src.int @ zero-extends src0 if needed.
4124 // t2.fp32 = vmov t1.i32
4125 // t3.fp = vcvt.{fp}.s32 @ fp is either f32 or f64
John Portoc31e2ed2015-09-11 05:17:08 -07004126 if (Src0->getType() != IceType_i32) {
4127 Variable *Src0R_32 = makeReg(IceType_i32);
4128 lowerCast(InstCast::create(Func, SourceIsSigned ? InstCast::Sext
4129 : InstCast::Zext,
4130 Src0R_32, Src0));
4131 Src0 = Src0R_32;
4132 }
4133 Variable *Src0R = legalizeToReg(Src0);
4134 Variable *Src0R_f32 = makeReg(IceType_f32);
John Portoba6a67c2015-09-25 15:19:45 -07004135 _mov(Src0R_f32, Src0R);
John Portoc31e2ed2015-09-11 05:17:08 -07004136 Src0R = Src0R_f32;
John Portoe88c7de2016-04-14 11:51:38 -07004137 Variable *T = makeReg(DestTy);
John Portoba6a67c2015-09-25 15:19:45 -07004138 const InstARM32Vcvt::VcvtVariant Conversion =
4139 DestIsF32
4140 ? (SourceIsSigned ? InstARM32Vcvt::Si2s : InstARM32Vcvt::Ui2s)
4141 : (SourceIsSigned ? InstARM32Vcvt::Si2d : InstARM32Vcvt::Ui2d);
4142 _vcvt(T, Src0R, Conversion);
John Portoc31e2ed2015-09-11 05:17:08 -07004143 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07004144 break;
4145 }
4146 case InstCast::Bitcast: {
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004147 Operand *Src0 = Instr->getSrc(0);
John Portoe88c7de2016-04-14 11:51:38 -07004148 if (DestTy == Src0->getType()) {
Jim Stichnoth54f3d512015-12-11 09:53:00 -08004149 auto *Assign = InstAssign::create(Func, Dest, Src0);
Jan Voung66c3d5e2015-06-04 17:02:31 -07004150 lowerAssign(Assign);
4151 return;
4152 }
John Portoe88c7de2016-04-14 11:51:38 -07004153 switch (DestTy) {
John Portof977f712015-09-14 16:28:33 -07004154 case IceType_NUM:
4155 case IceType_void:
4156 llvm::report_fatal_error("Unexpected bitcast.");
4157 case IceType_i1:
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004158 UnimplementedLoweringError(this, Instr);
John Portof977f712015-09-14 16:28:33 -07004159 break;
John Portof977f712015-09-14 16:28:33 -07004160 case IceType_i8:
John Porto7e6aa5a2016-03-02 15:10:19 -08004161 assert(Src0->getType() == IceType_v8i1);
4162 llvm::report_fatal_error(
4163 "i8 to v8i1 conversion should have been prelowered.");
John Portof977f712015-09-14 16:28:33 -07004164 break;
4165 case IceType_i16:
John Porto7e6aa5a2016-03-02 15:10:19 -08004166 assert(Src0->getType() == IceType_v16i1);
4167 llvm::report_fatal_error(
4168 "i16 to v16i1 conversion should have been prelowered.");
John Portof977f712015-09-14 16:28:33 -07004169 break;
4170 case IceType_i32:
4171 case IceType_f32: {
4172 Variable *Src0R = legalizeToReg(Src0);
John Portoe88c7de2016-04-14 11:51:38 -07004173 Variable *T = makeReg(DestTy);
John Portoba6a67c2015-09-25 15:19:45 -07004174 _mov(T, Src0R);
John Portof977f712015-09-14 16:28:33 -07004175 lowerAssign(InstAssign::create(Func, Dest, T));
4176 break;
4177 }
4178 case IceType_i64: {
4179 // t0, t1 <- src0
4180 // dest[31..0] = t0
4181 // dest[63..32] = t1
4182 assert(Src0->getType() == IceType_f64);
John Portoba6a67c2015-09-25 15:19:45 -07004183 auto *T = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
4184 T->initHiLo(Func);
John Portoe0b829f2015-09-28 09:50:48 -07004185 configureBitcastTemporary(T);
John Portof977f712015-09-14 16:28:33 -07004186 Variable *Src0R = legalizeToReg(Src0);
John Portoba6a67c2015-09-25 15:19:45 -07004187 _mov(T, Src0R);
John Porto1d937a82015-12-17 06:19:34 -08004188 Context.insert<InstFakeUse>(T->getHi());
4189 Context.insert<InstFakeUse>(T->getLo());
John Porto578f1162015-10-06 06:54:42 -07004190 lowerAssign(InstAssign::create(Func, Dest, T));
John Portof977f712015-09-14 16:28:33 -07004191 break;
4192 }
4193 case IceType_f64: {
4194 // T0 <- lo(src)
4195 // T1 <- hi(src)
4196 // vmov T2, T0, T1
4197 // Dest <- T2
4198 assert(Src0->getType() == IceType_i64);
John Portoe88c7de2016-04-14 11:51:38 -07004199 Variable *T = makeReg(DestTy);
John Portoba6a67c2015-09-25 15:19:45 -07004200 auto *Src64 = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
4201 Src64->initHiLo(Func);
John Portoe0b829f2015-09-28 09:50:48 -07004202 configureBitcastTemporary(Src64);
4203 lowerAssign(InstAssign::create(Func, Src64, Src0));
John Portoba6a67c2015-09-25 15:19:45 -07004204 _mov(T, Src64);
John Portof977f712015-09-14 16:28:33 -07004205 lowerAssign(InstAssign::create(Func, Dest, T));
4206 break;
4207 }
4208 case IceType_v8i1:
John Porto7e6aa5a2016-03-02 15:10:19 -08004209 assert(Src0->getType() == IceType_i8);
4210 llvm::report_fatal_error(
4211 "v8i1 to i8 conversion should have been prelowered.");
4212 break;
John Portof977f712015-09-14 16:28:33 -07004213 case IceType_v16i1:
John Porto7e6aa5a2016-03-02 15:10:19 -08004214 assert(Src0->getType() == IceType_i16);
4215 llvm::report_fatal_error(
4216 "v16i1 to i16 conversion should have been prelowered.");
4217 break;
4218 case IceType_v4i1:
John Portof977f712015-09-14 16:28:33 -07004219 case IceType_v8i16:
John Portof977f712015-09-14 16:28:33 -07004220 case IceType_v16i8:
John Portof977f712015-09-14 16:28:33 -07004221 case IceType_v4f32:
John Portoba6a67c2015-09-25 15:19:45 -07004222 case IceType_v4i32: {
John Portoe88c7de2016-04-14 11:51:38 -07004223 assert(typeWidthInBytes(DestTy) == typeWidthInBytes(Src0->getType()));
4224 assert(isVectorType(DestTy) == isVectorType(Src0->getType()));
4225 Variable *T = makeReg(DestTy);
John Porto7e6aa5a2016-03-02 15:10:19 -08004226 _mov(T, Src0);
4227 _mov(Dest, T);
John Portof977f712015-09-14 16:28:33 -07004228 break;
4229 }
John Portoba6a67c2015-09-25 15:19:45 -07004230 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07004231 break;
4232 }
4233 }
4234}
4235
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004236void TargetARM32::lowerExtractElement(const InstExtractElement *Instr) {
Eric Holk658bae22016-02-08 15:22:18 -08004237 Variable *Dest = Instr->getDest();
4238 Type DestTy = Dest->getType();
4239
4240 Variable *Src0 = legalizeToReg(Instr->getSrc(0));
4241 Operand *Src1 = Instr->getSrc(1);
4242
4243 if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src1)) {
4244 const uint32_t Index = Imm->getValue();
4245 Variable *T = makeReg(DestTy);
4246 Variable *TSrc0 = makeReg(Src0->getType());
4247
4248 if (isFloatingType(DestTy)) {
4249 // We need to make sure the source is in a suitable register.
4250 TSrc0->setRegClass(RegARM32::RCARM32_QtoS);
4251 }
4252
4253 _mov(TSrc0, Src0);
4254 _extractelement(T, TSrc0, Index);
4255 _mov(Dest, T);
4256 return;
4257 }
4258 assert(false && "extractelement requires a constant index");
Jan Voungb36ad9b2015-04-21 17:01:49 -07004259}
4260
John Porto2f5534f2015-09-18 15:59:47 -07004261namespace {
4262// Validates FCMPARM32_TABLE's declaration w.r.t. InstFcmp::FCondition ordering
4263// (and naming).
4264enum {
John Portoa4d100a2016-04-18 15:32:27 -07004265#define X(val, CC0, CC1, CC0_V, CC1_V, INV_V, NEG_V) _fcmp_ll_##val,
John Porto2f5534f2015-09-18 15:59:47 -07004266 FCMPARM32_TABLE
4267#undef X
4268 _fcmp_ll_NUM
4269};
4270
4271enum {
4272#define X(tag, str) _fcmp_hl_##tag = InstFcmp::tag,
4273 ICEINSTFCMP_TABLE
4274#undef X
4275 _fcmp_hl_NUM
4276};
4277
Jim Stichnothb0051df2016-01-13 11:39:15 -08004278static_assert((uint32_t)_fcmp_hl_NUM == (uint32_t)_fcmp_ll_NUM,
John Porto2f5534f2015-09-18 15:59:47 -07004279 "Inconsistency between high-level and low-level fcmp tags.");
4280#define X(tag, str) \
4281 static_assert( \
Jim Stichnothb0051df2016-01-13 11:39:15 -08004282 (uint32_t)_fcmp_hl_##tag == (uint32_t)_fcmp_ll_##tag, \
John Porto2f5534f2015-09-18 15:59:47 -07004283 "Inconsistency between high-level and low-level fcmp tag " #tag);
4284ICEINSTFCMP_TABLE
4285#undef X
4286
4287struct {
4288 CondARM32::Cond CC0;
4289 CondARM32::Cond CC1;
4290} TableFcmp[] = {
John Portoa4d100a2016-04-18 15:32:27 -07004291#define X(val, CC0, CC1, CC0_V, CC1_V, INV_V, NEG_V) \
John Porto2f5534f2015-09-18 15:59:47 -07004292 { CondARM32::CC0, CondARM32::CC1 } \
4293 ,
4294 FCMPARM32_TABLE
4295#undef X
4296};
John Portoccea7932015-11-17 04:58:36 -08004297
John Portodc619252016-02-10 15:57:16 -08004298bool isFloatingPointZero(const Operand *Src) {
4299 if (const auto *F32 = llvm::dyn_cast<const ConstantFloat>(Src)) {
John Portoccea7932015-11-17 04:58:36 -08004300 return Utils::isPositiveZero(F32->getValue());
4301 }
4302
John Portodc619252016-02-10 15:57:16 -08004303 if (const auto *F64 = llvm::dyn_cast<const ConstantDouble>(Src)) {
John Portoccea7932015-11-17 04:58:36 -08004304 return Utils::isPositiveZero(F64->getValue());
4305 }
4306
4307 return false;
4308}
John Porto2f5534f2015-09-18 15:59:47 -07004309} // end of anonymous namespace
4310
John Porto7b3d9cb2015-11-11 14:26:57 -08004311TargetARM32::CondWhenTrue TargetARM32::lowerFcmpCond(const InstFcmp *Instr) {
John Porto4a5e6d02015-11-04 09:32:55 -08004312 InstFcmp::FCond Condition = Instr->getCondition();
4313 switch (Condition) {
4314 case InstFcmp::False:
John Porto7b3d9cb2015-11-11 14:26:57 -08004315 return CondWhenTrue(CondARM32::kNone);
John Porto4a5e6d02015-11-04 09:32:55 -08004316 case InstFcmp::True:
John Porto7b3d9cb2015-11-11 14:26:57 -08004317 return CondWhenTrue(CondARM32::AL);
John Porto4a5e6d02015-11-04 09:32:55 -08004318 break;
4319 default: {
4320 Variable *Src0R = legalizeToReg(Instr->getSrc(0));
John Portoccea7932015-11-17 04:58:36 -08004321 Operand *Src1 = Instr->getSrc(1);
4322 if (isFloatingPointZero(Src1)) {
4323 _vcmp(Src0R, OperandARM32FlexFpZero::create(Func, Src0R->getType()));
4324 } else {
4325 _vcmp(Src0R, legalizeToReg(Src1));
4326 }
John Porto4a5e6d02015-11-04 09:32:55 -08004327 _vmrs();
4328 assert(Condition < llvm::array_lengthof(TableFcmp));
John Porto7b3d9cb2015-11-11 14:26:57 -08004329 return CondWhenTrue(TableFcmp[Condition].CC0, TableFcmp[Condition].CC1);
John Porto4a5e6d02015-11-04 09:32:55 -08004330 }
4331 }
4332}
4333
4334void TargetARM32::lowerFcmp(const InstFcmp *Instr) {
4335 Variable *Dest = Instr->getDest();
John Portoa4d100a2016-04-18 15:32:27 -07004336 const Type DestTy = Dest->getType();
4337
4338 if (isVectorType(DestTy)) {
4339 if (Instr->getCondition() == InstFcmp::False) {
4340 constexpr Type SafeTypeForMovingConstant = IceType_v4i32;
4341 auto *T = makeReg(SafeTypeForMovingConstant);
4342 _mov(T, llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)));
4343 _mov(Dest, T);
4344 return;
4345 }
4346
4347 if (Instr->getCondition() == InstFcmp::True) {
4348 constexpr Type SafeTypeForMovingConstant = IceType_v4i32;
4349 auto *T = makeReg(SafeTypeForMovingConstant);
4350 _mov(T, llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(1)));
4351 _mov(Dest, T);
4352 return;
4353 }
4354
4355 Variable *T0;
4356 Variable *T1;
4357 bool Negate = false;
4358 auto *Src0 = legalizeToReg(Instr->getSrc(0));
4359 auto *Src1 = legalizeToReg(Instr->getSrc(1));
4360
4361 switch (Instr->getCondition()) {
4362 default:
4363 llvm::report_fatal_error("Unhandled fp comparison.");
4364#define _Vcnone(Tptr, S0, S1) \
4365 do { \
4366 *(Tptr) = nullptr; \
4367 } while (0)
4368#define _Vceq(Tptr, S0, S1) \
4369 do { \
4370 *(Tptr) = makeReg(DestTy); \
4371 _vceq(*(Tptr), S0, S1); \
4372 } while (0)
4373#define _Vcge(Tptr, S0, S1) \
4374 do { \
4375 *(Tptr) = makeReg(DestTy); \
4376 _vcge(*(Tptr), S0, S1)->setSignType(InstARM32::FS_Signed); \
4377 } while (0)
4378#define _Vcgt(Tptr, S0, S1) \
4379 do { \
4380 *(Tptr) = makeReg(DestTy); \
4381 _vcgt(*(Tptr), S0, S1)->setSignType(InstARM32::FS_Signed); \
4382 } while (0)
4383#define X(val, CC0, CC1, CC0_V, CC1_V, INV_V, NEG_V) \
4384 case InstFcmp::val: { \
4385 _Vc##CC0_V(&T0, (INV_V) ? Src1 : Src0, (INV_V) ? Src0 : Src1); \
4386 _Vc##CC1_V(&T1, (INV_V) ? Src0 : Src1, (INV_V) ? Src1 : Src0); \
4387 Negate = NEG_V; \
4388 } break;
4389 FCMPARM32_TABLE
4390#undef X
4391#undef _Vcgt
4392#undef _Vcge
4393#undef _Vceq
4394#undef _Vcnone
4395 }
4396 assert(T0 != nullptr);
4397 Variable *T = T0;
4398 if (T1 != nullptr) {
4399 T = makeReg(DestTy);
4400 _vorr(T, T0, T1);
4401 }
4402
4403 if (Negate) {
4404 auto *TNeg = makeReg(DestTy);
4405 _vmvn(TNeg, T);
4406 T = TNeg;
4407 }
4408
4409 _mov(Dest, T);
John Porto2f5534f2015-09-18 15:59:47 -07004410 return;
4411 }
4412
Karl Schimpfb9f27222015-11-09 12:09:58 -08004413 Variable *T = makeReg(IceType_i1);
John Porto7b3d9cb2015-11-11 14:26:57 -08004414 Operand *_1 = legalize(Ctx->getConstantInt32(1), Legal_Reg | Legal_Flex);
4415 Operand *_0 =
4416 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
John Porto4a5e6d02015-11-04 09:32:55 -08004417
John Porto7b3d9cb2015-11-11 14:26:57 -08004418 CondWhenTrue Cond = lowerFcmpCond(Instr);
John Porto4a5e6d02015-11-04 09:32:55 -08004419
4420 bool RedefineT = false;
John Porto7b3d9cb2015-11-11 14:26:57 -08004421 if (Cond.WhenTrue0 != CondARM32::AL) {
4422 _mov(T, _0);
John Porto4a5e6d02015-11-04 09:32:55 -08004423 RedefineT = true;
John Porto2f5534f2015-09-18 15:59:47 -07004424 }
John Porto4a5e6d02015-11-04 09:32:55 -08004425
John Porto7b3d9cb2015-11-11 14:26:57 -08004426 if (Cond.WhenTrue0 == CondARM32::kNone) {
4427 _mov(Dest, T);
4428 return;
John Porto2f5534f2015-09-18 15:59:47 -07004429 }
John Porto4a5e6d02015-11-04 09:32:55 -08004430
John Porto7b3d9cb2015-11-11 14:26:57 -08004431 if (RedefineT) {
4432 _mov_redefined(T, _1, Cond.WhenTrue0);
4433 } else {
4434 _mov(T, _1, Cond.WhenTrue0);
4435 }
4436
4437 if (Cond.WhenTrue1 != CondARM32::kNone) {
4438 _mov_redefined(T, _1, Cond.WhenTrue1);
John Porto4a5e6d02015-11-04 09:32:55 -08004439 }
4440
John Porto2f5534f2015-09-18 15:59:47 -07004441 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07004442}
4443
John Portoccea7932015-11-17 04:58:36 -08004444TargetARM32::CondWhenTrue
4445TargetARM32::lowerInt64IcmpCond(InstIcmp::ICond Condition, Operand *Src0,
4446 Operand *Src1) {
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004447 assert(Condition < llvm::array_lengthof(TableIcmp64));
John Porto7b3d9cb2015-11-11 14:26:57 -08004448
John Portoccea7932015-11-17 04:58:36 -08004449 Int32Operands SrcsLo(loOperand(Src0), loOperand(Src1));
4450 Int32Operands SrcsHi(hiOperand(Src0), hiOperand(Src1));
4451 assert(SrcsLo.hasConstOperand() == SrcsHi.hasConstOperand());
4452 assert(SrcsLo.swappedOperands() == SrcsHi.swappedOperands());
4453
4454 if (SrcsLo.hasConstOperand()) {
4455 const uint32_t ValueLo = SrcsLo.getConstantValue();
4456 const uint32_t ValueHi = SrcsHi.getConstantValue();
4457 const uint64_t Value = (static_cast<uint64_t>(ValueHi) << 32) | ValueLo;
4458 if ((Condition == InstIcmp::Eq || Condition == InstIcmp::Ne) &&
4459 Value == 0) {
4460 Variable *T = makeReg(IceType_i32);
4461 Variable *Src0LoR = SrcsLo.src0R(this);
4462 Variable *Src0HiR = SrcsHi.src0R(this);
4463 _orrs(T, Src0LoR, Src0HiR);
John Porto1d937a82015-12-17 06:19:34 -08004464 Context.insert<InstFakeUse>(T);
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004465 return CondWhenTrue(TableIcmp64[Condition].C1);
John Portoccea7932015-11-17 04:58:36 -08004466 }
4467
4468 Variable *Src0RLo = SrcsLo.src0R(this);
4469 Variable *Src0RHi = SrcsHi.src0R(this);
4470 Operand *Src1RFLo = SrcsLo.src1RF(this);
4471 Operand *Src1RFHi = ValueLo == ValueHi ? Src1RFLo : SrcsHi.src1RF(this);
4472
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004473 const bool UseRsb =
4474 TableIcmp64[Condition].Swapped != SrcsLo.swappedOperands();
John Portoccea7932015-11-17 04:58:36 -08004475
4476 if (UseRsb) {
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004477 if (TableIcmp64[Condition].IsSigned) {
John Portoccea7932015-11-17 04:58:36 -08004478 Variable *T = makeReg(IceType_i32);
4479 _rsbs(T, Src0RLo, Src1RFLo);
John Porto1d937a82015-12-17 06:19:34 -08004480 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004481
4482 T = makeReg(IceType_i32);
4483 _rscs(T, Src0RHi, Src1RFHi);
4484 // We need to add a FakeUse here because liveness gets mad at us (Def
4485 // without Use.) Note that flag-setting instructions are considered to
4486 // have side effects and, therefore, are not DCE'ed.
John Porto1d937a82015-12-17 06:19:34 -08004487 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004488 } else {
4489 Variable *T = makeReg(IceType_i32);
4490 _rsbs(T, Src0RHi, Src1RFHi);
John Porto1d937a82015-12-17 06:19:34 -08004491 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004492
4493 T = makeReg(IceType_i32);
4494 _rsbs(T, Src0RLo, Src1RFLo, CondARM32::EQ);
John Porto1d937a82015-12-17 06:19:34 -08004495 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004496 }
4497 } else {
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004498 if (TableIcmp64[Condition].IsSigned) {
John Portoccea7932015-11-17 04:58:36 -08004499 _cmp(Src0RLo, Src1RFLo);
4500 Variable *T = makeReg(IceType_i32);
4501 _sbcs(T, Src0RHi, Src1RFHi);
John Porto1d937a82015-12-17 06:19:34 -08004502 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004503 } else {
4504 _cmp(Src0RHi, Src1RFHi);
4505 _cmp(Src0RLo, Src1RFLo, CondARM32::EQ);
4506 }
4507 }
4508
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004509 return CondWhenTrue(TableIcmp64[Condition].C1);
John Portoccea7932015-11-17 04:58:36 -08004510 }
4511
4512 Variable *Src0RLo, *Src0RHi;
4513 Operand *Src1RFLo, *Src1RFHi;
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004514 if (TableIcmp64[Condition].Swapped) {
John Portoccea7932015-11-17 04:58:36 -08004515 Src0RLo = legalizeToReg(loOperand(Src1));
4516 Src0RHi = legalizeToReg(hiOperand(Src1));
4517 Src1RFLo = legalizeToReg(loOperand(Src0));
4518 Src1RFHi = legalizeToReg(hiOperand(Src0));
4519 } else {
4520 Src0RLo = legalizeToReg(loOperand(Src0));
4521 Src0RHi = legalizeToReg(hiOperand(Src0));
4522 Src1RFLo = legalizeToReg(loOperand(Src1));
4523 Src1RFHi = legalizeToReg(hiOperand(Src1));
4524 }
Jan Voung3bfd99a2015-05-22 16:35:25 -07004525
Jan Voung3bfd99a2015-05-22 16:35:25 -07004526 // a=icmp cond, b, c ==>
4527 // GCC does:
4528 // cmp b.hi, c.hi or cmp b.lo, c.lo
4529 // cmp.eq b.lo, c.lo sbcs t1, b.hi, c.hi
4530 // mov.<C1> t, #1 mov.<C1> t, #1
4531 // mov.<C2> t, #0 mov.<C2> t, #0
4532 // mov a, t mov a, t
4533 // where the "cmp.eq b.lo, c.lo" is used for unsigned and "sbcs t1, hi, hi"
Andrew Scull57e12682015-09-16 11:30:19 -07004534 // is used for signed compares. In some cases, b and c need to be swapped as
4535 // well.
Jan Voung3bfd99a2015-05-22 16:35:25 -07004536 //
4537 // LLVM does:
4538 // for EQ and NE:
4539 // eor t1, b.hi, c.hi
4540 // eor t2, b.lo, c.hi
4541 // orrs t, t1, t2
4542 // mov.<C> t, #1
4543 // mov a, t
4544 //
Andrew Scull57e12682015-09-16 11:30:19 -07004545 // that's nice in that it's just as short but has fewer dependencies for
4546 // better ILP at the cost of more registers.
Jan Voung3bfd99a2015-05-22 16:35:25 -07004547 //
Andrew Scull57e12682015-09-16 11:30:19 -07004548 // Otherwise for signed/unsigned <, <=, etc. LLVM uses a sequence with two
4549 // unconditional mov #0, two cmps, two conditional mov #1, and one
4550 // conditional reg mov. That has few dependencies for good ILP, but is a
4551 // longer sequence.
Jan Voung3bfd99a2015-05-22 16:35:25 -07004552 //
4553 // So, we are going with the GCC version since it's usually better (except
4554 // perhaps for eq/ne). We could revisit special-casing eq/ne later.
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004555 if (TableIcmp64[Condition].IsSigned) {
John Portoccea7932015-11-17 04:58:36 -08004556 Variable *ScratchReg = makeReg(IceType_i32);
4557 _cmp(Src0RLo, Src1RFLo);
4558 _sbcs(ScratchReg, Src0RHi, Src1RFHi);
4559 // ScratchReg isn't going to be used, but we need the side-effect of
4560 // setting flags from this operation.
John Porto1d937a82015-12-17 06:19:34 -08004561 Context.insert<InstFakeUse>(ScratchReg);
John Portoccea7932015-11-17 04:58:36 -08004562 } else {
4563 _cmp(Src0RHi, Src1RFHi);
4564 _cmp(Src0RLo, Src1RFLo, CondARM32::EQ);
4565 }
Jim Stichnoth2d6c8262016-02-07 09:50:27 -08004566 return CondWhenTrue(TableIcmp64[Condition].C1);
John Portoccea7932015-11-17 04:58:36 -08004567}
John Porto4a5e6d02015-11-04 09:32:55 -08004568
John Portoccea7932015-11-17 04:58:36 -08004569TargetARM32::CondWhenTrue
4570TargetARM32::lowerInt32IcmpCond(InstIcmp::ICond Condition, Operand *Src0,
4571 Operand *Src1) {
4572 Int32Operands Srcs(Src0, Src1);
4573 if (!Srcs.hasConstOperand()) {
4574
4575 Variable *Src0R = Srcs.src0R(this);
4576 Operand *Src1RF = Srcs.src1RF(this);
4577 _cmp(Src0R, Src1RF);
4578 return CondWhenTrue(getIcmp32Mapping(Condition));
Jan Voung3bfd99a2015-05-22 16:35:25 -07004579 }
4580
John Portoccea7932015-11-17 04:58:36 -08004581 Variable *Src0R = Srcs.src0R(this);
4582 const int32_t Value = Srcs.getConstantValue();
4583 if ((Condition == InstIcmp::Eq || Condition == InstIcmp::Ne) && Value == 0) {
4584 _tst(Src0R, Src0R);
4585 return CondWhenTrue(getIcmp32Mapping(Condition));
4586 }
4587
4588 if (!Srcs.swappedOperands() && !Srcs.immediateIsFlexEncodable() &&
4589 Srcs.negatedImmediateIsFlexEncodable()) {
4590 Operand *Src1F = Srcs.negatedSrc1F(this);
4591 _cmn(Src0R, Src1F);
4592 return CondWhenTrue(getIcmp32Mapping(Condition));
4593 }
4594
4595 Operand *Src1RF = Srcs.src1RF(this);
4596 if (!Srcs.swappedOperands()) {
4597 _cmp(Src0R, Src1RF);
4598 } else {
4599 Variable *T = makeReg(IceType_i32);
4600 _rsbs(T, Src0R, Src1RF);
John Porto1d937a82015-12-17 06:19:34 -08004601 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004602 }
4603 return CondWhenTrue(getIcmp32Mapping(Condition));
4604}
4605
4606TargetARM32::CondWhenTrue
4607TargetARM32::lowerInt8AndInt16IcmpCond(InstIcmp::ICond Condition, Operand *Src0,
4608 Operand *Src1) {
4609 Int32Operands Srcs(Src0, Src1);
4610 const int32_t ShAmt = 32 - getScalarIntBitWidth(Src0->getType());
4611 assert(ShAmt >= 0);
4612
4613 if (!Srcs.hasConstOperand()) {
4614 Variable *Src0R = makeReg(IceType_i32);
John Porto2758bb02015-11-17 14:31:25 -08004615 Operand *ShAmtImm = shAmtImm(ShAmt);
4616 _lsl(Src0R, legalizeToReg(Src0), ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08004617
4618 Variable *Src1R = legalizeToReg(Src1);
Jim Stichnoth54f3d512015-12-11 09:53:00 -08004619 auto *Src1F = OperandARM32FlexReg::create(Func, IceType_i32, Src1R,
4620 OperandARM32::LSL, ShAmtImm);
John Portoccea7932015-11-17 04:58:36 -08004621 _cmp(Src0R, Src1F);
4622 return CondWhenTrue(getIcmp32Mapping(Condition));
4623 }
4624
4625 const int32_t Value = Srcs.getConstantValue();
4626 if ((Condition == InstIcmp::Eq || Condition == InstIcmp::Ne) && Value == 0) {
John Porto2758bb02015-11-17 14:31:25 -08004627 Operand *ShAmtImm = shAmtImm(ShAmt);
John Portoccea7932015-11-17 04:58:36 -08004628 Variable *T = makeReg(IceType_i32);
John Porto2758bb02015-11-17 14:31:25 -08004629 _lsls(T, Srcs.src0R(this), ShAmtImm);
John Porto1d937a82015-12-17 06:19:34 -08004630 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004631 return CondWhenTrue(getIcmp32Mapping(Condition));
4632 }
4633
4634 Variable *ConstR = makeReg(IceType_i32);
4635 _mov(ConstR,
4636 legalize(Ctx->getConstantInt32(Value << ShAmt), Legal_Reg | Legal_Flex));
4637 Operand *NonConstF = OperandARM32FlexReg::create(
4638 Func, IceType_i32, Srcs.src0R(this), OperandARM32::LSL,
4639 Ctx->getConstantInt32(ShAmt));
4640
4641 if (Srcs.swappedOperands()) {
4642 _cmp(ConstR, NonConstF);
4643 } else {
4644 Variable *T = makeReg(IceType_i32);
4645 _rsbs(T, ConstR, NonConstF);
John Porto1d937a82015-12-17 06:19:34 -08004646 Context.insert<InstFakeUse>(T);
John Portoccea7932015-11-17 04:58:36 -08004647 }
4648 return CondWhenTrue(getIcmp32Mapping(Condition));
4649}
4650
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004651TargetARM32::CondWhenTrue TargetARM32::lowerIcmpCond(const InstIcmp *Instr) {
John Porto4b6e4b42016-02-17 05:00:59 -08004652 return lowerIcmpCond(Instr->getCondition(), Instr->getSrc(0),
4653 Instr->getSrc(1));
4654}
John Portoccea7932015-11-17 04:58:36 -08004655
John Porto4b6e4b42016-02-17 05:00:59 -08004656TargetARM32::CondWhenTrue TargetARM32::lowerIcmpCond(InstIcmp::ICond Condition,
4657 Operand *Src0,
4658 Operand *Src1) {
4659 Src0 = legalizeUndef(Src0);
4660 Src1 = legalizeUndef(Src1);
4661
Jan Voung3bfd99a2015-05-22 16:35:25 -07004662 // a=icmp cond b, c ==>
4663 // GCC does:
4664 // <u/s>xtb tb, b
4665 // <u/s>xtb tc, c
4666 // cmp tb, tc
4667 // mov.C1 t, #0
4668 // mov.C2 t, #1
4669 // mov a, t
Andrew Scull57e12682015-09-16 11:30:19 -07004670 // where the unsigned/sign extension is not needed for 32-bit. They also have
4671 // special cases for EQ and NE. E.g., for NE:
Jan Voung3bfd99a2015-05-22 16:35:25 -07004672 // <extend to tb, tc>
4673 // subs t, tb, tc
4674 // movne t, #1
4675 // mov a, t
4676 //
4677 // LLVM does:
4678 // lsl tb, b, #<N>
4679 // mov t, #0
4680 // cmp tb, c, lsl #<N>
4681 // mov.<C> t, #1
4682 // mov a, t
4683 //
Andrew Scull57e12682015-09-16 11:30:19 -07004684 // the left shift is by 0, 16, or 24, which allows the comparison to focus on
4685 // the digits that actually matter (for 16-bit or 8-bit signed/unsigned). For
4686 // the unsigned case, for some reason it does similar to GCC and does a uxtb
4687 // first. It's not clear to me why that special-casing is needed.
Jan Voung3bfd99a2015-05-22 16:35:25 -07004688 //
Andrew Scull57e12682015-09-16 11:30:19 -07004689 // We'll go with the LLVM way for now, since it's shorter and has just as few
4690 // dependencies.
John Portoccea7932015-11-17 04:58:36 -08004691 switch (Src0->getType()) {
4692 default:
4693 llvm::report_fatal_error("Unhandled type in lowerIcmpCond");
Eric Holkcc69fa22016-02-10 13:07:06 -08004694 case IceType_i1:
John Portoccea7932015-11-17 04:58:36 -08004695 case IceType_i8:
4696 case IceType_i16:
4697 return lowerInt8AndInt16IcmpCond(Condition, Src0, Src1);
4698 case IceType_i32:
4699 return lowerInt32IcmpCond(Condition, Src0, Src1);
4700 case IceType_i64:
4701 return lowerInt64IcmpCond(Condition, Src0, Src1);
Jan Voung3bfd99a2015-05-22 16:35:25 -07004702 }
John Porto4a5e6d02015-11-04 09:32:55 -08004703}
4704
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004705void TargetARM32::lowerIcmp(const InstIcmp *Instr) {
4706 Variable *Dest = Instr->getDest();
John Portoa4d100a2016-04-18 15:32:27 -07004707 const Type DestTy = Dest->getType();
John Porto4a5e6d02015-11-04 09:32:55 -08004708
John Portoa4d100a2016-04-18 15:32:27 -07004709 if (isVectorType(DestTy)) {
4710 auto *T = makeReg(DestTy);
4711 auto *Src0 = legalizeToReg(Instr->getSrc(0));
4712 auto *Src1 = legalizeToReg(Instr->getSrc(1));
4713 const Type SrcTy = Src0->getType();
4714
4715 bool NeedsShl = false;
4716 Type NewTypeAfterShl;
4717 SizeT ShAmt;
4718 switch (SrcTy) {
4719 default:
4720 break;
4721 case IceType_v16i1:
4722 NeedsShl = true;
4723 NewTypeAfterShl = IceType_v16i8;
4724 ShAmt = 7;
4725 break;
4726 case IceType_v8i1:
4727 NeedsShl = true;
4728 NewTypeAfterShl = IceType_v8i16;
4729 ShAmt = 15;
4730 break;
4731 case IceType_v4i1:
4732 NeedsShl = true;
4733 NewTypeAfterShl = IceType_v4i32;
4734 ShAmt = 31;
4735 break;
4736 }
4737
4738 if (NeedsShl) {
4739 auto *Imm = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(ShAmt));
4740 auto *Src0T = makeReg(NewTypeAfterShl);
4741 auto *Src0Shl = makeReg(NewTypeAfterShl);
4742 _mov(Src0T, Src0);
4743 _vshl(Src0Shl, Src0T, Imm);
4744 Src0 = Src0Shl;
4745
4746 auto *Src1T = makeReg(NewTypeAfterShl);
4747 auto *Src1Shl = makeReg(NewTypeAfterShl);
4748 _mov(Src1T, Src1);
4749 _vshl(Src1Shl, Src1T, Imm);
4750 Src1 = Src1Shl;
4751 }
4752
4753 switch (Instr->getCondition()) {
4754 default:
4755 llvm::report_fatal_error("Unhandled integer comparison.");
4756#define _Vceq(T, S0, S1, Signed) _vceq(T, S0, S1)
4757#define _Vcge(T, S0, S1, Signed) \
4758 _vcge(T, S0, S1) \
4759 ->setSignType(Signed ? InstARM32::FS_Signed : InstARM32::FS_Unsigned)
4760#define _Vcgt(T, S0, S1, Signed) \
4761 _vcgt(T, S0, S1) \
4762 ->setSignType(Signed ? InstARM32::FS_Signed : InstARM32::FS_Unsigned)
4763#define X(val, is_signed, swapped64, C_32, C1_64, C2_64, C_V, INV_V, NEG_V) \
4764 case InstIcmp::val: { \
4765 _Vc##C_V(T, (INV_V) ? Src1 : Src0, (INV_V) ? Src0 : Src1, is_signed); \
4766 if (NEG_V) { \
4767 auto *TInv = makeReg(DestTy); \
4768 _vmvn(TInv, T); \
4769 T = TInv; \
4770 } \
4771 } break;
4772 ICMPARM32_TABLE
4773#undef X
4774#undef _Vcgt
4775#undef _Vcge
4776#undef _Vceq
4777 }
4778 _mov(Dest, T);
John Porto4a5e6d02015-11-04 09:32:55 -08004779 return;
4780 }
4781
John Porto7b3d9cb2015-11-11 14:26:57 -08004782 Operand *_0 =
4783 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
4784 Operand *_1 = legalize(Ctx->getConstantInt32(1), Legal_Reg | Legal_Flex);
Karl Schimpfb9f27222015-11-09 12:09:58 -08004785 Variable *T = makeReg(IceType_i1);
John Porto4a5e6d02015-11-04 09:32:55 -08004786
John Porto7b3d9cb2015-11-11 14:26:57 -08004787 _mov(T, _0);
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004788 CondWhenTrue Cond = lowerIcmpCond(Instr);
John Porto7b3d9cb2015-11-11 14:26:57 -08004789 _mov_redefined(T, _1, Cond.WhenTrue0);
Jan Voung3bfd99a2015-05-22 16:35:25 -07004790 _mov(Dest, T);
John Porto4a5e6d02015-11-04 09:32:55 -08004791
John Porto7b3d9cb2015-11-11 14:26:57 -08004792 assert(Cond.WhenTrue1 == CondARM32::kNone);
4793
Jan Voung3bfd99a2015-05-22 16:35:25 -07004794 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07004795}
4796
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08004797void TargetARM32::lowerInsertElement(const InstInsertElement *Instr) {
Eric Holk658bae22016-02-08 15:22:18 -08004798 Variable *Dest = Instr->getDest();
4799 Type DestTy = Dest->getType();
4800
4801 Variable *Src0 = legalizeToReg(Instr->getSrc(0));
4802 Variable *Src1 = legalizeToReg(Instr->getSrc(1));
4803 Operand *Src2 = Instr->getSrc(2);
4804
4805 if (const auto *Imm = llvm::dyn_cast<ConstantInteger32>(Src2)) {
4806 const uint32_t Index = Imm->getValue();
4807 Variable *T = makeReg(DestTy);
4808
4809 if (isFloatingType(DestTy)) {
4810 T->setRegClass(RegARM32::RCARM32_QtoS);
4811 }
4812
4813 _mov(T, Src0);
4814 _insertelement(T, Src1, Index);
4815 _set_dest_redefined();
4816 _mov(Dest, T);
4817 return;
4818 }
4819 assert(false && "insertelement requires a constant index");
Jan Voungb36ad9b2015-04-21 17:01:49 -07004820}
4821
John Porto578f1162015-10-06 06:54:42 -07004822namespace {
4823inline uint64_t getConstantMemoryOrder(Operand *Opnd) {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07004824 if (auto *Integer = llvm::dyn_cast<ConstantInteger32>(Opnd))
John Porto578f1162015-10-06 06:54:42 -07004825 return Integer->getValue();
4826 return Intrinsics::MemoryOrderInvalid;
4827}
4828} // end of anonymous namespace
4829
John Porto4b6e4b42016-02-17 05:00:59 -08004830void TargetARM32::lowerLoadLinkedStoreExclusive(
4831 Type Ty, Operand *Addr, std::function<Variable *(Variable *)> Operation,
4832 CondARM32::Cond Cond) {
4833
4834 auto *Retry = Context.insert<InstARM32Label>(this);
John Porto324334e2016-03-08 11:00:53 -08004835
John Porto4b6e4b42016-02-17 05:00:59 -08004836 { // scoping for loop highlighting.
John Porto324334e2016-03-08 11:00:53 -08004837 Variable *Success = makeReg(IceType_i32);
John Porto4b6e4b42016-02-17 05:00:59 -08004838 Variable *Tmp = (Ty == IceType_i64) ? makeI64RegPair() : makeReg(Ty);
John Porto4b6e4b42016-02-17 05:00:59 -08004839 auto *_0 = Ctx->getConstantZero(IceType_i32);
4840
4841 Context.insert<InstFakeDef>(Tmp);
4842 Context.insert<InstFakeUse>(Tmp);
4843 Variable *AddrR = legalizeToReg(Addr);
4844 _ldrex(Tmp, formMemoryOperand(AddrR, Ty))->setDestRedefined();
4845 auto *StoreValue = Operation(Tmp);
4846 assert(StoreValue->mustHaveReg());
John Porto324334e2016-03-08 11:00:53 -08004847 // strex requires Dest to be a register other than Value or Addr. This
4848 // restriction is cleanly represented by adding an "early" definition of
4849 // Dest (or a latter use of all the sources.)
4850 Context.insert<InstFakeDef>(Success);
4851 if (Cond != CondARM32::AL) {
4852 _mov_redefined(Success, legalize(_0, Legal_Reg | Legal_Flex),
4853 InstARM32::getOppositeCondition(Cond));
4854 }
4855 _strex(Success, StoreValue, formMemoryOperand(AddrR, Ty), Cond)
4856 ->setDestRedefined();
4857 _cmp(Success, _0);
John Porto4b6e4b42016-02-17 05:00:59 -08004858 }
John Porto324334e2016-03-08 11:00:53 -08004859
John Porto4b6e4b42016-02-17 05:00:59 -08004860 _br(Retry, CondARM32::NE);
4861}
4862
4863namespace {
4864InstArithmetic *createArithInst(Cfg *Func, uint32_t Operation, Variable *Dest,
4865 Variable *Src0, Operand *Src1) {
4866 InstArithmetic::OpKind Oper;
4867 switch (Operation) {
4868 default:
4869 llvm::report_fatal_error("Unknown AtomicRMW operation");
4870 case Intrinsics::AtomicExchange:
4871 llvm::report_fatal_error("Can't handle Atomic xchg operation");
4872 case Intrinsics::AtomicAdd:
4873 Oper = InstArithmetic::Add;
4874 break;
4875 case Intrinsics::AtomicAnd:
4876 Oper = InstArithmetic::And;
4877 break;
4878 case Intrinsics::AtomicSub:
4879 Oper = InstArithmetic::Sub;
4880 break;
4881 case Intrinsics::AtomicOr:
4882 Oper = InstArithmetic::Or;
4883 break;
4884 case Intrinsics::AtomicXor:
4885 Oper = InstArithmetic::Xor;
4886 break;
4887 }
4888 return InstArithmetic::create(Func, Oper, Dest, Src0, Src1);
4889}
4890} // end of anonymous namespace
4891
John Porto578f1162015-10-06 06:54:42 -07004892void TargetARM32::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
John Porto4b6e4b42016-02-17 05:00:59 -08004893 Operand *Addr, Operand *Val) {
John Porto578f1162015-10-06 06:54:42 -07004894 // retry:
John Porto4b6e4b42016-02-17 05:00:59 -08004895 // ldrex tmp, [addr]
4896 // mov contents, tmp
4897 // op result, contents, Val
4898 // strex success, result, [addr]
4899 // cmp success, 0
John Porto578f1162015-10-06 06:54:42 -07004900 // jne retry
4901 // fake-use(addr, operand) @ prevents undesirable clobbering.
4902 // mov dest, contents
John Porto4b6e4b42016-02-17 05:00:59 -08004903 auto DestTy = Dest->getType();
John Porto578f1162015-10-06 06:54:42 -07004904
4905 if (DestTy == IceType_i64) {
John Porto4b6e4b42016-02-17 05:00:59 -08004906 lowerInt64AtomicRMW(Dest, Operation, Addr, Val);
Jan Voungb36ad9b2015-04-21 17:01:49 -07004907 return;
John Porto578f1162015-10-06 06:54:42 -07004908 }
John Porto578f1162015-10-06 06:54:42 -07004909
John Porto4b6e4b42016-02-17 05:00:59 -08004910 Operand *ValRF = nullptr;
4911 if (llvm::isa<ConstantInteger32>(Val)) {
4912 ValRF = Val;
John Porto578f1162015-10-06 06:54:42 -07004913 } else {
John Porto4b6e4b42016-02-17 05:00:59 -08004914 ValRF = legalizeToReg(Val);
John Porto578f1162015-10-06 06:54:42 -07004915 }
John Porto4b6e4b42016-02-17 05:00:59 -08004916 auto *ContentsR = makeReg(DestTy);
4917 auto *ResultR = makeReg(DestTy);
4918
John Porto578f1162015-10-06 06:54:42 -07004919 _dmb();
John Porto4b6e4b42016-02-17 05:00:59 -08004920 lowerLoadLinkedStoreExclusive(
4921 DestTy, Addr,
4922 [this, Operation, ResultR, ContentsR, ValRF](Variable *Tmp) {
4923 lowerAssign(InstAssign::create(Func, ContentsR, Tmp));
4924 if (Operation == Intrinsics::AtomicExchange) {
4925 lowerAssign(InstAssign::create(Func, ResultR, ValRF));
4926 } else {
4927 lowerArithmetic(
4928 createArithInst(Func, Operation, ResultR, ContentsR, ValRF));
4929 }
4930 return ResultR;
4931 });
4932 _dmb();
4933 if (auto *ValR = llvm::dyn_cast<Variable>(ValRF)) {
4934 Context.insert<InstFakeUse>(ValR);
4935 }
4936 // Can't dce ContentsR.
4937 Context.insert<InstFakeUse>(ContentsR);
4938 lowerAssign(InstAssign::create(Func, Dest, ContentsR));
4939}
4940
4941void TargetARM32::lowerInt64AtomicRMW(Variable *Dest, uint32_t Operation,
4942 Operand *Addr, Operand *Val) {
4943 assert(Dest->getType() == IceType_i64);
4944
4945 auto *ResultR = makeI64RegPair();
4946
4947 Context.insert<InstFakeDef>(ResultR);
4948
4949 Operand *ValRF = nullptr;
4950 if (llvm::dyn_cast<ConstantInteger64>(Val)) {
4951 ValRF = Val;
4952 } else {
4953 auto *ValR64 = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
4954 ValR64->initHiLo(Func);
4955 ValR64->setMustNotHaveReg();
4956 ValR64->getLo()->setMustHaveReg();
4957 ValR64->getHi()->setMustHaveReg();
4958 lowerAssign(InstAssign::create(Func, ValR64, Val));
4959 ValRF = ValR64;
John Porto578f1162015-10-06 06:54:42 -07004960 }
4961
John Porto4b6e4b42016-02-17 05:00:59 -08004962 auto *ContentsR = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
4963 ContentsR->initHiLo(Func);
4964 ContentsR->setMustNotHaveReg();
4965 ContentsR->getLo()->setMustHaveReg();
4966 ContentsR->getHi()->setMustHaveReg();
4967
4968 _dmb();
4969 lowerLoadLinkedStoreExclusive(
4970 IceType_i64, Addr,
4971 [this, Operation, ResultR, ContentsR, ValRF](Variable *Tmp) {
4972 lowerAssign(InstAssign::create(Func, ContentsR, Tmp));
4973 Context.insert<InstFakeUse>(Tmp);
4974 if (Operation == Intrinsics::AtomicExchange) {
4975 lowerAssign(InstAssign::create(Func, ResultR, ValRF));
4976 } else {
4977 lowerArithmetic(
4978 createArithInst(Func, Operation, ResultR, ContentsR, ValRF));
4979 }
4980 Context.insert<InstFakeUse>(ResultR->getHi());
4981 Context.insert<InstFakeDef>(ResultR, ResultR->getLo())
4982 ->setDestRedefined();
4983 return ResultR;
4984 });
4985 _dmb();
4986 if (auto *ValR64 = llvm::dyn_cast<Variable64On32>(ValRF)) {
4987 Context.insert<InstFakeUse>(ValR64->getLo());
4988 Context.insert<InstFakeUse>(ValR64->getHi());
John Porto578f1162015-10-06 06:54:42 -07004989 }
John Porto4b6e4b42016-02-17 05:00:59 -08004990 lowerAssign(InstAssign::create(Func, Dest, ContentsR));
John Porto578f1162015-10-06 06:54:42 -07004991}
4992
John Portoc39ec102015-12-01 13:00:43 -08004993void TargetARM32::postambleCtpop64(const InstCall *Instr) {
4994 Operand *Arg0 = Instr->getArg(0);
4995 if (isInt32Asserting32Or64(Arg0->getType())) {
4996 return;
4997 }
4998 // The popcount helpers always return 32-bit values, while the intrinsic's
4999 // signature matches some 64-bit platform's native instructions and expect to
5000 // fill a 64-bit reg. Thus, clear the upper bits of the dest just in case the
5001 // user doesn't do that in the IR or doesn't toss the bits via truncate.
Jim Stichnoth54f3d512015-12-11 09:53:00 -08005002 auto *DestHi = llvm::cast<Variable>(hiOperand(Instr->getDest()));
John Portoc39ec102015-12-01 13:00:43 -08005003 Variable *T = makeReg(IceType_i32);
5004 Operand *_0 =
5005 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
5006 _mov(T, _0);
5007 _mov(DestHi, T);
5008}
5009
John Porto578f1162015-10-06 06:54:42 -07005010void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
5011 Variable *Dest = Instr->getDest();
5012 Type DestTy = (Dest != nullptr) ? Dest->getType() : IceType_void;
5013 Intrinsics::IntrinsicID ID = Instr->getIntrinsicInfo().ID;
5014 switch (ID) {
5015 case Intrinsics::AtomicFence:
Jan Voungb36ad9b2015-04-21 17:01:49 -07005016 case Intrinsics::AtomicFenceAll:
John Porto578f1162015-10-06 06:54:42 -07005017 assert(Dest == nullptr);
5018 _dmb();
Jan Voungb36ad9b2015-04-21 17:01:49 -07005019 return;
5020 case Intrinsics::AtomicIsLockFree: {
John Porto578f1162015-10-06 06:54:42 -07005021 Operand *ByteSize = Instr->getArg(0);
5022 auto *CI = llvm::dyn_cast<ConstantInteger32>(ByteSize);
5023 if (CI == nullptr) {
5024 // The PNaCl ABI requires the byte size to be a compile-time constant.
5025 Func->setError("AtomicIsLockFree byte size should be compile-time const");
5026 return;
5027 }
5028 static constexpr int32_t NotLockFree = 0;
5029 static constexpr int32_t LockFree = 1;
5030 int32_t Result = NotLockFree;
5031 switch (CI->getValue()) {
5032 case 1:
5033 case 2:
5034 case 4:
5035 case 8:
5036 Result = LockFree;
5037 break;
5038 }
5039 _mov(Dest, legalizeToReg(Ctx->getConstantInt32(Result)));
Jan Voungb36ad9b2015-04-21 17:01:49 -07005040 return;
5041 }
5042 case Intrinsics::AtomicLoad: {
John Porto578f1162015-10-06 06:54:42 -07005043 assert(isScalarIntegerType(DestTy));
5044 // We require the memory address to be naturally aligned. Given that is the
5045 // case, then normal loads are atomic.
5046 if (!Intrinsics::isMemoryOrderValid(
5047 ID, getConstantMemoryOrder(Instr->getArg(1)))) {
5048 Func->setError("Unexpected memory ordering for AtomicLoad");
5049 return;
5050 }
5051 Variable *T;
5052
5053 if (DestTy == IceType_i64) {
5054 // ldrex is the only arm instruction that is guaranteed to load a 64-bit
5055 // integer atomically. Everything else works with a regular ldr.
5056 T = makeI64RegPair();
5057 _ldrex(T, formMemoryOperand(Instr->getArg(0), IceType_i64));
5058 } else {
5059 T = makeReg(DestTy);
5060 _ldr(T, formMemoryOperand(Instr->getArg(0), DestTy));
5061 }
5062 _dmb();
5063 lowerAssign(InstAssign::create(Func, Dest, T));
John Porto4b6e4b42016-02-17 05:00:59 -08005064 // Adding a fake-use T to ensure the atomic load is not removed if Dest is
5065 // unused.
5066 Context.insert<InstFakeUse>(T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005067 return;
5068 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07005069 case Intrinsics::AtomicStore: {
John Porto578f1162015-10-06 06:54:42 -07005070 // We require the memory address to be naturally aligned. Given that is the
5071 // case, then normal loads are atomic.
5072 if (!Intrinsics::isMemoryOrderValid(
5073 ID, getConstantMemoryOrder(Instr->getArg(2)))) {
5074 Func->setError("Unexpected memory ordering for AtomicStore");
5075 return;
5076 }
John Porto578f1162015-10-06 06:54:42 -07005077
John Porto4b6e4b42016-02-17 05:00:59 -08005078 auto *Value = Instr->getArg(0);
5079 if (Value->getType() == IceType_i64) {
5080 auto *ValueR = makeI64RegPair();
5081 Context.insert<InstFakeDef>(ValueR);
5082 lowerAssign(InstAssign::create(Func, ValueR, Value));
John Porto578f1162015-10-06 06:54:42 -07005083 _dmb();
John Porto4b6e4b42016-02-17 05:00:59 -08005084 lowerLoadLinkedStoreExclusive(
5085 IceType_i64, Instr->getArg(1), [this, ValueR](Variable *Tmp) {
5086 // The following fake-use prevents the ldrex instruction from being
5087 // dead code eliminated.
5088 Context.insert<InstFakeUse>(llvm::cast<Variable>(loOperand(Tmp)));
5089 Context.insert<InstFakeUse>(llvm::cast<Variable>(hiOperand(Tmp)));
5090 Context.insert<InstFakeUse>(Tmp);
5091 return ValueR;
5092 });
5093 Context.insert<InstFakeUse>(ValueR);
John Porto578f1162015-10-06 06:54:42 -07005094 _dmb();
5095 return;
5096 }
John Porto4b6e4b42016-02-17 05:00:59 -08005097
5098 auto *ValueR = legalizeToReg(Instr->getArg(0));
5099 const auto ValueTy = ValueR->getType();
5100 assert(isScalarIntegerType(ValueTy));
5101 auto *Addr = legalizeToReg(Instr->getArg(1));
5102
John Porto578f1162015-10-06 06:54:42 -07005103 // non-64-bit stores are atomically as long as the address is aligned. This
5104 // is PNaCl, so addresses are aligned.
John Porto578f1162015-10-06 06:54:42 -07005105 _dmb();
John Porto4b6e4b42016-02-17 05:00:59 -08005106 _str(ValueR, formMemoryOperand(Addr, ValueTy));
John Porto578f1162015-10-06 06:54:42 -07005107 _dmb();
5108 return;
5109 }
5110 case Intrinsics::AtomicCmpxchg: {
John Porto578f1162015-10-06 06:54:42 -07005111 // retry:
5112 // ldrex tmp, [addr]
5113 // cmp tmp, expected
5114 // mov expected, tmp
John Porto578f1162015-10-06 06:54:42 -07005115 // strexeq success, new, [addr]
John Porto578f1162015-10-06 06:54:42 -07005116 // cmpeq success, #0
5117 // bne retry
5118 // mov dest, expected
John Porto578f1162015-10-06 06:54:42 -07005119 assert(isScalarIntegerType(DestTy));
5120 // We require the memory address to be naturally aligned. Given that is the
5121 // case, then normal loads are atomic.
5122 if (!Intrinsics::isMemoryOrderValid(
5123 ID, getConstantMemoryOrder(Instr->getArg(3)),
5124 getConstantMemoryOrder(Instr->getArg(4)))) {
5125 Func->setError("Unexpected memory ordering for AtomicCmpxchg");
5126 return;
5127 }
5128
John Porto578f1162015-10-06 06:54:42 -07005129 if (DestTy == IceType_i64) {
John Porto324334e2016-03-08 11:00:53 -08005130 Variable *LoadedValue = nullptr;
5131
John Porto4b6e4b42016-02-17 05:00:59 -08005132 auto *New = makeI64RegPair();
John Porto1d937a82015-12-17 06:19:34 -08005133 Context.insert<InstFakeDef>(New);
John Porto4b6e4b42016-02-17 05:00:59 -08005134 lowerAssign(InstAssign::create(Func, New, Instr->getArg(2)));
5135
5136 auto *Expected = makeI64RegPair();
5137 Context.insert<InstFakeDef>(Expected);
5138 lowerAssign(InstAssign::create(Func, Expected, Instr->getArg(1)));
5139
5140 _dmb();
5141 lowerLoadLinkedStoreExclusive(
5142 DestTy, Instr->getArg(0),
John Porto324334e2016-03-08 11:00:53 -08005143 [this, Expected, New, Instr, DestTy, &LoadedValue](Variable *Tmp) {
John Porto4b6e4b42016-02-17 05:00:59 -08005144 auto *ExpectedLoR = llvm::cast<Variable>(loOperand(Expected));
5145 auto *ExpectedHiR = llvm::cast<Variable>(hiOperand(Expected));
5146 auto *TmpLoR = llvm::cast<Variable>(loOperand(Tmp));
5147 auto *TmpHiR = llvm::cast<Variable>(hiOperand(Tmp));
5148 _cmp(TmpLoR, ExpectedLoR);
5149 _cmp(TmpHiR, ExpectedHiR, CondARM32::EQ);
John Porto324334e2016-03-08 11:00:53 -08005150 LoadedValue = Tmp;
John Porto4b6e4b42016-02-17 05:00:59 -08005151 return New;
5152 },
5153 CondARM32::EQ);
5154 _dmb();
5155
John Porto324334e2016-03-08 11:00:53 -08005156 Context.insert<InstFakeUse>(LoadedValue);
5157 lowerAssign(InstAssign::create(Func, Dest, LoadedValue));
John Porto4b6e4b42016-02-17 05:00:59 -08005158 // The fake-use Expected prevents the assignments to Expected (above)
5159 // from being removed if Dest is not used.
5160 Context.insert<InstFakeUse>(Expected);
5161 // New needs to be alive here, or its live range will end in the
5162 // strex instruction.
5163 Context.insert<InstFakeUse>(New);
5164 return;
John Porto578f1162015-10-06 06:54:42 -07005165 }
John Porto4b6e4b42016-02-17 05:00:59 -08005166
5167 auto *New = legalizeToReg(Instr->getArg(2));
5168 auto *Expected = legalizeToReg(Instr->getArg(1));
John Porto324334e2016-03-08 11:00:53 -08005169 Variable *LoadedValue = nullptr;
John Porto4b6e4b42016-02-17 05:00:59 -08005170
5171 _dmb();
5172 lowerLoadLinkedStoreExclusive(
John Porto324334e2016-03-08 11:00:53 -08005173 DestTy, Instr->getArg(0),
5174 [this, Expected, New, Instr, DestTy, &LoadedValue](Variable *Tmp) {
John Porto4b6e4b42016-02-17 05:00:59 -08005175 lowerIcmpCond(InstIcmp::Eq, Tmp, Expected);
John Porto324334e2016-03-08 11:00:53 -08005176 LoadedValue = Tmp;
John Porto4b6e4b42016-02-17 05:00:59 -08005177 return New;
John Porto324334e2016-03-08 11:00:53 -08005178 },
5179 CondARM32::EQ);
John Porto578f1162015-10-06 06:54:42 -07005180 _dmb();
5181
John Porto324334e2016-03-08 11:00:53 -08005182 lowerAssign(InstAssign::create(Func, Dest, LoadedValue));
John Porto1d937a82015-12-17 06:19:34 -08005183 Context.insert<InstFakeUse>(Expected);
John Porto4b6e4b42016-02-17 05:00:59 -08005184 Context.insert<InstFakeUse>(New);
John Porto578f1162015-10-06 06:54:42 -07005185 return;
5186 }
5187 case Intrinsics::AtomicRMW: {
5188 if (!Intrinsics::isMemoryOrderValid(
5189 ID, getConstantMemoryOrder(Instr->getArg(3)))) {
5190 Func->setError("Unexpected memory ordering for AtomicRMW");
5191 return;
5192 }
5193 lowerAtomicRMW(
5194 Dest, static_cast<uint32_t>(
5195 llvm::cast<ConstantInteger32>(Instr->getArg(0))->getValue()),
5196 Instr->getArg(1), Instr->getArg(2));
Jan Voungb36ad9b2015-04-21 17:01:49 -07005197 return;
5198 }
5199 case Intrinsics::Bswap: {
Jan Voungf645d852015-07-09 10:35:09 -07005200 Operand *Val = Instr->getArg(0);
5201 Type Ty = Val->getType();
5202 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07005203 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07005204 Variable *Val_Lo = legalizeToReg(loOperand(Val));
5205 Variable *Val_Hi = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07005206 Variable *T_Lo = makeReg(IceType_i32);
5207 Variable *T_Hi = makeReg(IceType_i32);
Jim Stichnoth54f3d512015-12-11 09:53:00 -08005208 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
5209 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Jan Voungf645d852015-07-09 10:35:09 -07005210 _rev(T_Lo, Val_Lo);
5211 _rev(T_Hi, Val_Hi);
5212 _mov(DestLo, T_Hi);
5213 _mov(DestHi, T_Lo);
5214 } else {
5215 assert(Ty == IceType_i32 || Ty == IceType_i16);
Andrew Scull97f460d2015-07-21 10:07:42 -07005216 Variable *ValR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07005217 Variable *T = makeReg(Ty);
5218 _rev(T, ValR);
5219 if (Val->getType() == IceType_i16) {
John Porto2758bb02015-11-17 14:31:25 -08005220 Operand *_16 = shAmtImm(16);
5221 _lsr(T, T, _16);
Jan Voungf645d852015-07-09 10:35:09 -07005222 }
5223 _mov(Dest, T);
5224 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07005225 return;
5226 }
5227 case Intrinsics::Ctpop: {
John Portoc39ec102015-12-01 13:00:43 -08005228 llvm::report_fatal_error("Ctpop should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005229 }
5230 case Intrinsics::Ctlz: {
Andrew Scull57e12682015-09-16 11:30:19 -07005231 // The "is zero undef" parameter is ignored and we always return a
5232 // well-defined value.
Jan Voungf645d852015-07-09 10:35:09 -07005233 Operand *Val = Instr->getArg(0);
5234 Variable *ValLoR;
5235 Variable *ValHiR = nullptr;
5236 if (Val->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07005237 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07005238 ValLoR = legalizeToReg(loOperand(Val));
5239 ValHiR = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07005240 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07005241 ValLoR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07005242 }
John Porto578f1162015-10-06 06:54:42 -07005243 lowerCLZ(Dest, ValLoR, ValHiR);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005244 return;
5245 }
5246 case Intrinsics::Cttz: {
Jan Voungf645d852015-07-09 10:35:09 -07005247 // Essentially like Clz, but reverse the bits first.
5248 Operand *Val = Instr->getArg(0);
5249 Variable *ValLoR;
5250 Variable *ValHiR = nullptr;
5251 if (Val->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07005252 Val = legalizeUndef(Val);
Andrew Scull97f460d2015-07-21 10:07:42 -07005253 ValLoR = legalizeToReg(loOperand(Val));
5254 ValHiR = legalizeToReg(hiOperand(Val));
Jan Voungf645d852015-07-09 10:35:09 -07005255 Variable *TLo = makeReg(IceType_i32);
5256 Variable *THi = makeReg(IceType_i32);
5257 _rbit(TLo, ValLoR);
5258 _rbit(THi, ValHiR);
5259 ValLoR = THi;
5260 ValHiR = TLo;
5261 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07005262 ValLoR = legalizeToReg(Val);
Jan Voungf645d852015-07-09 10:35:09 -07005263 Variable *T = makeReg(IceType_i32);
5264 _rbit(T, ValLoR);
5265 ValLoR = T;
5266 }
John Porto578f1162015-10-06 06:54:42 -07005267 lowerCLZ(Dest, ValLoR, ValHiR);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005268 return;
5269 }
5270 case Intrinsics::Fabs: {
John Portoba6a67c2015-09-25 15:19:45 -07005271 Variable *T = makeReg(DestTy);
John Portoba6a67c2015-09-25 15:19:45 -07005272 _vabs(T, legalizeToReg(Instr->getArg(0)));
5273 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005274 return;
5275 }
5276 case Intrinsics::Longjmp: {
John Portoc39ec102015-12-01 13:00:43 -08005277 llvm::report_fatal_error("longjmp should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005278 }
5279 case Intrinsics::Memcpy: {
John Portoc39ec102015-12-01 13:00:43 -08005280 llvm::report_fatal_error("memcpy should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005281 }
5282 case Intrinsics::Memmove: {
John Portoc39ec102015-12-01 13:00:43 -08005283 llvm::report_fatal_error("memmove should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005284 }
5285 case Intrinsics::Memset: {
John Portoc39ec102015-12-01 13:00:43 -08005286 llvm::report_fatal_error("memmove should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005287 }
5288 case Intrinsics::NaClReadTP: {
John Portodc619252016-02-10 15:57:16 -08005289 if (SandboxingType != ST_NaCl) {
John Porto52b51572015-12-05 14:16:25 -08005290 llvm::report_fatal_error("nacl-read-tp should have been prelowered.");
5291 }
5292 Variable *TP = legalizeToReg(OperandARM32Mem::create(
5293 Func, getPointerType(), getPhysicalRegister(RegARM32::Reg_r9),
5294 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))));
5295 _mov(Dest, TP);
5296 return;
Jan Voungb36ad9b2015-04-21 17:01:49 -07005297 }
5298 case Intrinsics::Setjmp: {
John Portoc39ec102015-12-01 13:00:43 -08005299 llvm::report_fatal_error("setjmp should have been prelowered.");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005300 }
5301 case Intrinsics::Sqrt: {
Nicolas Capens956cfd62016-10-31 14:28:09 -04005302 assert(isScalarFloatingType(Dest->getType()) ||
5303 getFlags().getApplicationBinaryInterface() != ::Ice::ABI_PNaCl);
Jan Voung86ebec12015-08-09 07:58:35 -07005304 Variable *Src = legalizeToReg(Instr->getArg(0));
Nicolas Capens8d90a342017-09-27 14:33:11 -04005305 Variable *T = makeReg(DestTy);
Jan Voung86ebec12015-08-09 07:58:35 -07005306 _vsqrt(T, Src);
John Portoba6a67c2015-09-25 15:19:45 -07005307 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005308 return;
5309 }
5310 case Intrinsics::Stacksave: {
Jan Voungf645d852015-07-09 10:35:09 -07005311 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
Jan Voungf645d852015-07-09 10:35:09 -07005312 _mov(Dest, SP);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005313 return;
5314 }
5315 case Intrinsics::Stackrestore: {
John Porto52b51572015-12-05 14:16:25 -08005316 Variable *Val = legalizeToReg(Instr->getArg(0));
5317 Sandboxer(this).reset_sp(Val);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005318 return;
5319 }
5320 case Intrinsics::Trap:
Jan Voungf645d852015-07-09 10:35:09 -07005321 _trap();
Jan Voungb36ad9b2015-04-21 17:01:49 -07005322 return;
Casey Dahlinb40560b2017-06-28 13:58:58 -07005323 case Intrinsics::AddSaturateSigned:
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005324 case Intrinsics::AddSaturateUnsigned: {
Casey Dahlinb40560b2017-06-28 13:58:58 -07005325 bool Unsigned = (ID == Intrinsics::AddSaturateUnsigned);
5326 Variable *Src0 = legalizeToReg(Instr->getArg(0));
5327 Variable *Src1 = legalizeToReg(Instr->getArg(1));
5328 Variable *T = makeReg(DestTy);
5329 _vqadd(T, Src0, Src1, Unsigned);
5330 _mov(Dest, T);
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005331 return;
5332 }
Nicolas Capensacfb3df2016-10-03 10:46:30 -04005333 case Intrinsics::LoadSubVector: {
Nicolas Capens675e15b2017-09-27 15:06:35 -04005334 assert(llvm::isa<ConstantInteger32>(Instr->getArg(1)) &&
5335 "LoadSubVector second argument must be a constant");
5336 Variable *Dest = Instr->getDest();
5337 Type Ty = Dest->getType();
5338 auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(1));
5339 Operand *Addr = Instr->getArg(0);
5340 OperandARM32Mem *Src = formMemoryOperand(Addr, Ty);
5341 doMockBoundsCheck(Src);
5342
5343 if (Dest->isRematerializable()) {
5344 Context.insert<InstFakeDef>(Dest);
5345 return;
5346 }
5347
5348 auto *T = makeReg(Ty);
5349 switch (SubVectorSize->getValue()) {
5350 case 4:
5351 _vldr1d(T, Src);
5352 break;
5353 case 8:
5354 _vldr1q(T, Src);
5355 break;
5356 default:
5357 Func->setError("Unexpected size for LoadSubVector");
5358 return;
5359 }
Nicolas Capensf6951fa2017-10-02 10:44:03 -04005360 _mov(Dest, T);
Nicolas Capensacfb3df2016-10-03 10:46:30 -04005361 return;
5362 }
5363 case Intrinsics::StoreSubVector: {
Nicolas Capens675e15b2017-09-27 15:06:35 -04005364 assert(llvm::isa<ConstantInteger32>(Instr->getArg(2)) &&
5365 "StoreSubVector third argument must be a constant");
5366 auto *SubVectorSize = llvm::cast<ConstantInteger32>(Instr->getArg(2));
5367 Variable *Value = legalizeToReg(Instr->getArg(0));
5368 Operand *Addr = Instr->getArg(1);
5369 OperandARM32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
5370 doMockBoundsCheck(NewAddr);
5371
5372 Value = legalizeToReg(Value);
5373
5374 switch (SubVectorSize->getValue()) {
5375 case 4:
5376 _vstr1d(Value, NewAddr);
5377 break;
5378 case 8:
5379 _vstr1q(Value, NewAddr);
5380 break;
5381 default:
5382 Func->setError("Unexpected size for StoreSubVector");
5383 return;
5384 }
Nicolas Capensacfb3df2016-10-03 10:46:30 -04005385 return;
5386 }
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005387 case Intrinsics::MultiplyAddPairs: {
Nicolas Capens675e15b2017-09-27 15:06:35 -04005388 Variable *Src0 = legalizeToReg(Instr->getArg(0));
5389 Variable *Src1 = legalizeToReg(Instr->getArg(1));
5390 Variable *T = makeReg(DestTy);
5391 _vmlap(T, Src0, Src1);
5392 _mov(Dest, T);
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005393 return;
5394 }
Nicolas Capens675e15b2017-09-27 15:06:35 -04005395 case Intrinsics::MultiplyHighSigned:
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005396 case Intrinsics::MultiplyHighUnsigned: {
Nicolas Capens675e15b2017-09-27 15:06:35 -04005397 bool Unsigned = (ID == Intrinsics::MultiplyHighUnsigned);
5398 Variable *Src0 = legalizeToReg(Instr->getArg(0));
5399 Variable *Src1 = legalizeToReg(Instr->getArg(1));
5400 Variable *T = makeReg(DestTy);
5401 _vmulh(T, Src0, Src1, Unsigned);
5402 _mov(Dest, T);
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005403 return;
5404 }
5405 case Intrinsics::Nearbyint: {
5406 UnimplementedLoweringError(this, Instr);
5407 return;
5408 }
5409 case Intrinsics::Round: {
5410 UnimplementedLoweringError(this, Instr);
5411 return;
5412 }
5413 case Intrinsics::SignMask: {
5414 UnimplementedLoweringError(this, Instr);
5415 return;
5416 }
Casey Dahlinb40560b2017-06-28 13:58:58 -07005417 case Intrinsics::SubtractSaturateSigned:
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005418 case Intrinsics::SubtractSaturateUnsigned: {
Casey Dahlinb40560b2017-06-28 13:58:58 -07005419 bool Unsigned = (ID == Intrinsics::SubtractSaturateUnsigned);
5420 Variable *Src0 = legalizeToReg(Instr->getArg(0));
5421 Variable *Src1 = legalizeToReg(Instr->getArg(1));
5422 Variable *T = makeReg(DestTy);
5423 _vqsub(T, Src0, Src1, Unsigned);
5424 _mov(Dest, T);
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005425 return;
5426 }
Nicolas Capens675e15b2017-09-27 15:06:35 -04005427 case Intrinsics::VectorPackSigned:
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005428 case Intrinsics::VectorPackUnsigned: {
Nicolas Capens675e15b2017-09-27 15:06:35 -04005429 bool Unsigned = (ID == Intrinsics::VectorPackUnsigned);
5430 bool Saturating = true;
5431 Variable *Src0 = legalizeToReg(Instr->getArg(0));
5432 Variable *Src1 = legalizeToReg(Instr->getArg(1));
5433 Variable *T = makeReg(DestTy);
5434 _vqmovn2(T, Src0, Src1, Unsigned, Saturating);
5435 _mov(Dest, T);
Nicolas Capens48a3fc72017-04-18 15:14:16 -04005436 return;
5437 }
Jim Stichnoth7145e692016-10-19 05:49:47 -07005438 default: // UnknownIntrinsic
5439 Func->setError("Unexpected intrinsic");
Jan Voungb36ad9b2015-04-21 17:01:49 -07005440 return;
5441 }
5442 return;
5443}
5444
Jan Voungf645d852015-07-09 10:35:09 -07005445void TargetARM32::lowerCLZ(Variable *Dest, Variable *ValLoR, Variable *ValHiR) {
5446 Type Ty = Dest->getType();
5447 assert(Ty == IceType_i32 || Ty == IceType_i64);
5448 Variable *T = makeReg(IceType_i32);
5449 _clz(T, ValLoR);
5450 if (Ty == IceType_i64) {
Jim Stichnoth54f3d512015-12-11 09:53:00 -08005451 auto *DestLo = llvm::cast<Variable>(loOperand(Dest));
5452 auto *DestHi = llvm::cast<Variable>(hiOperand(Dest));
Jan Voungf645d852015-07-09 10:35:09 -07005453 Operand *Zero =
5454 legalize(Ctx->getConstantZero(IceType_i32), Legal_Reg | Legal_Flex);
5455 Operand *ThirtyTwo =
5456 legalize(Ctx->getConstantInt32(32), Legal_Reg | Legal_Flex);
5457 _cmp(ValHiR, Zero);
5458 Variable *T2 = makeReg(IceType_i32);
5459 _add(T2, T, ThirtyTwo);
5460 _clz(T2, ValHiR, CondARM32::NE);
Andrew Scull57e12682015-09-16 11:30:19 -07005461 // T2 is actually a source as well when the predicate is not AL (since it
Jim Stichnoth230d4102015-09-25 17:40:32 -07005462 // may leave T2 alone). We use _set_dest_redefined to prolong the liveness
Andrew Scull57e12682015-09-16 11:30:19 -07005463 // of T2 as if it was used as a source.
Jim Stichnoth230d4102015-09-25 17:40:32 -07005464 _set_dest_redefined();
Jan Voungf645d852015-07-09 10:35:09 -07005465 _mov(DestLo, T2);
John Portoba6a67c2015-09-25 15:19:45 -07005466 Variable *T3 = makeReg(Zero->getType());
Jan Voung28068ad2015-07-31 12:58:46 -07005467 _mov(T3, Zero);
5468 _mov(DestHi, T3);
Jan Voungf645d852015-07-09 10:35:09 -07005469 return;
5470 }
5471 _mov(Dest, T);
5472 return;
5473}
5474
Jan Voungbefd03a2015-06-02 11:03:03 -07005475void TargetARM32::lowerLoad(const InstLoad *Load) {
Andrew Scull57e12682015-09-16 11:30:19 -07005476 // A Load instruction can be treated the same as an Assign instruction, after
5477 // the source operand is transformed into an OperandARM32Mem operand.
Jan Voungbefd03a2015-06-02 11:03:03 -07005478 Type Ty = Load->getDest()->getType();
5479 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
5480 Variable *DestLoad = Load->getDest();
5481
Andrew Scull57e12682015-09-16 11:30:19 -07005482 // TODO(jvoung): handled folding opportunities. Sign and zero extension can
5483 // be folded into a load.
Jim Stichnoth54f3d512015-12-11 09:53:00 -08005484 auto *Assign = InstAssign::create(Func, DestLoad, Src0);
Jan Voungbefd03a2015-06-02 11:03:03 -07005485 lowerAssign(Assign);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005486}
5487
John Portof5f02f72015-11-09 14:52:40 -08005488namespace {
5489void dumpAddressOpt(const Cfg *Func, const Variable *Base, int32_t Offset,
5490 const Variable *OffsetReg, int16_t OffsetRegShAmt,
5491 const Inst *Reason) {
5492 if (!BuildDefs::dump())
5493 return;
5494 if (!Func->isVerbose(IceV_AddrOpt))
5495 return;
5496 OstreamLocker _(Func->getContext());
5497 Ostream &Str = Func->getContext()->getStrDump();
5498 Str << "Instruction: ";
5499 Reason->dumpDecorated(Func);
5500 Str << " results in Base=";
5501 if (Base)
5502 Base->dump(Func);
5503 else
5504 Str << "<null>";
5505 Str << ", OffsetReg=";
5506 if (OffsetReg)
5507 OffsetReg->dump(Func);
5508 else
5509 Str << "<null>";
5510 Str << ", Shift=" << OffsetRegShAmt << ", Offset=" << Offset << "\n";
5511}
5512
5513bool matchAssign(const VariablesMetadata *VMetadata, Variable **Var,
5514 int32_t *Offset, const Inst **Reason) {
5515 // Var originates from Var=SrcVar ==> set Var:=SrcVar
5516 if (*Var == nullptr)
5517 return false;
5518 const Inst *VarAssign = VMetadata->getSingleDefinition(*Var);
5519 if (!VarAssign)
5520 return false;
5521 assert(!VMetadata->isMultiDef(*Var));
5522 if (!llvm::isa<InstAssign>(VarAssign))
5523 return false;
5524
5525 Operand *SrcOp = VarAssign->getSrc(0);
John Porto6f534712016-01-20 10:49:38 -08005526 bool Optimized = false;
John Portof5f02f72015-11-09 14:52:40 -08005527 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) {
5528 if (!VMetadata->isMultiDef(SrcVar) ||
5529 // TODO: ensure SrcVar stays single-BB
5530 false) {
John Porto6f534712016-01-20 10:49:38 -08005531 Optimized = true;
John Portof5f02f72015-11-09 14:52:40 -08005532 *Var = SrcVar;
5533 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) {
5534 int32_t MoreOffset = Const->getValue();
5535 int32_t NewOffset = MoreOffset + *Offset;
5536 if (Utils::WouldOverflowAdd(*Offset, MoreOffset))
5537 return false;
5538 *Var = nullptr;
5539 *Offset += NewOffset;
John Porto6f534712016-01-20 10:49:38 -08005540 Optimized = true;
John Portof5f02f72015-11-09 14:52:40 -08005541 }
John Portof5f02f72015-11-09 14:52:40 -08005542 }
5543
John Porto6f534712016-01-20 10:49:38 -08005544 if (Optimized) {
5545 *Reason = VarAssign;
5546 }
5547
5548 return Optimized;
John Portof5f02f72015-11-09 14:52:40 -08005549}
5550
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08005551bool isAddOrSub(const Inst *Instr, InstArithmetic::OpKind *Kind) {
5552 if (const auto *Arith = llvm::dyn_cast<InstArithmetic>(Instr)) {
John Portof5f02f72015-11-09 14:52:40 -08005553 switch (Arith->getOp()) {
5554 default:
5555 return false;
5556 case InstArithmetic::Add:
5557 case InstArithmetic::Sub:
5558 *Kind = Arith->getOp();
5559 return true;
5560 }
5561 }
5562 return false;
5563}
5564
5565bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, Variable **Base,
5566 Variable **OffsetReg, int32_t OffsetRegShamt,
5567 const Inst **Reason) {
5568 // OffsetReg==nullptr && Base is Base=Var1+Var2 ==>
5569 // set Base=Var1, OffsetReg=Var2, Shift=0
5570 if (*Base == nullptr)
5571 return false;
5572 if (*OffsetReg != nullptr)
5573 return false;
5574 (void)OffsetRegShamt;
5575 assert(OffsetRegShamt == 0);
5576 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base);
5577 if (BaseInst == nullptr)
5578 return false;
5579 assert(!VMetadata->isMultiDef(*Base));
5580 if (BaseInst->getSrcSize() < 2)
5581 return false;
5582 auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0));
5583 if (!Var1)
5584 return false;
5585 if (VMetadata->isMultiDef(Var1))
5586 return false;
5587 auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1));
5588 if (!Var2)
5589 return false;
5590 if (VMetadata->isMultiDef(Var2))
5591 return false;
5592 InstArithmetic::OpKind _;
5593 if (!isAddOrSub(BaseInst, &_) ||
5594 // TODO: ensure Var1 and Var2 stay single-BB
5595 false)
5596 return false;
5597 *Base = Var1;
5598 *OffsetReg = Var2;
5599 // OffsetRegShamt is already 0.
5600 *Reason = BaseInst;
5601 return true;
5602}
5603
5604bool matchShiftedOffsetReg(const VariablesMetadata *VMetadata,
5605 Variable **OffsetReg, OperandARM32::ShiftKind *Kind,
5606 int32_t *OffsetRegShamt, const Inst **Reason) {
5607 // OffsetReg is OffsetReg=Var*Const && log2(Const)+Shift<=32 ==>
5608 // OffsetReg=Var, Shift+=log2(Const)
5609 // OffsetReg is OffsetReg=Var<<Const && Const+Shift<=32 ==>
5610 // OffsetReg=Var, Shift+=Const
5611 // OffsetReg is OffsetReg=Var>>Const && Const-Shift>=-32 ==>
5612 // OffsetReg=Var, Shift-=Const
5613 OperandARM32::ShiftKind NewShiftKind = OperandARM32::kNoShift;
5614 if (*OffsetReg == nullptr)
5615 return false;
5616 auto *IndexInst = VMetadata->getSingleDefinition(*OffsetReg);
5617 if (IndexInst == nullptr)
5618 return false;
5619 assert(!VMetadata->isMultiDef(*OffsetReg));
5620 if (IndexInst->getSrcSize() < 2)
5621 return false;
5622 auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst);
5623 if (ArithInst == nullptr)
5624 return false;
5625 auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0));
5626 if (Var == nullptr)
5627 return false;
5628 auto *Const = llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1));
5629 if (Const == nullptr) {
5630 assert(!llvm::isa<ConstantInteger32>(ArithInst->getSrc(0)));
5631 return false;
5632 }
5633 if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32)
5634 return false;
5635
5636 uint32_t NewShamt = -1;
5637 switch (ArithInst->getOp()) {
5638 default:
5639 return false;
5640 case InstArithmetic::Shl: {
5641 NewShiftKind = OperandARM32::LSL;
5642 NewShamt = Const->getValue();
5643 if (NewShamt > 31)
5644 return false;
5645 } break;
5646 case InstArithmetic::Lshr: {
5647 NewShiftKind = OperandARM32::LSR;
5648 NewShamt = Const->getValue();
5649 if (NewShamt > 31)
5650 return false;
5651 } break;
5652 case InstArithmetic::Ashr: {
5653 NewShiftKind = OperandARM32::ASR;
5654 NewShamt = Const->getValue();
5655 if (NewShamt > 31)
5656 return false;
5657 } break;
5658 case InstArithmetic::Udiv:
5659 case InstArithmetic::Mul: {
5660 const uint32_t UnsignedConst = Const->getValue();
5661 NewShamt = llvm::findFirstSet(UnsignedConst);
5662 if (NewShamt != llvm::findLastSet(UnsignedConst)) {
5663 // First bit set is not the same as the last bit set, so Const is not
5664 // a power of 2.
5665 return false;
5666 }
5667 NewShiftKind = ArithInst->getOp() == InstArithmetic::Udiv
5668 ? OperandARM32::LSR
5669 : OperandARM32::LSL;
5670 } break;
5671 }
5672 // Allowed "transitions":
5673 // kNoShift -> * iff NewShamt < 31
5674 // LSL -> LSL iff NewShamt + OffsetRegShamt < 31
5675 // LSR -> LSR iff NewShamt + OffsetRegShamt < 31
5676 // ASR -> ASR iff NewShamt + OffsetRegShamt < 31
5677 if (*Kind != OperandARM32::kNoShift && *Kind != NewShiftKind) {
5678 return false;
5679 }
5680 const int32_t NewOffsetRegShamt = *OffsetRegShamt + NewShamt;
5681 if (NewOffsetRegShamt > 31)
5682 return false;
5683 *OffsetReg = Var;
5684 *OffsetRegShamt = NewOffsetRegShamt;
5685 *Kind = NewShiftKind;
5686 *Reason = IndexInst;
5687 return true;
5688}
5689
5690bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable **Base,
5691 int32_t *Offset, const Inst **Reason) {
5692 // Base is Base=Var+Const || Base is Base=Const+Var ==>
5693 // set Base=Var, Offset+=Const
5694 // Base is Base=Var-Const ==>
5695 // set Base=Var, Offset-=Const
5696 if (*Base == nullptr)
5697 return false;
5698 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base);
5699 if (BaseInst == nullptr) {
5700 return false;
5701 }
5702 assert(!VMetadata->isMultiDef(*Base));
5703
5704 auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst);
5705 if (ArithInst == nullptr)
5706 return false;
5707 InstArithmetic::OpKind Kind;
5708 if (!isAddOrSub(ArithInst, &Kind))
5709 return false;
5710 bool IsAdd = Kind == InstArithmetic::Add;
5711 Operand *Src0 = ArithInst->getSrc(0);
5712 Operand *Src1 = ArithInst->getSrc(1);
5713 auto *Var0 = llvm::dyn_cast<Variable>(Src0);
5714 auto *Var1 = llvm::dyn_cast<Variable>(Src1);
5715 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0);
5716 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1);
5717 Variable *NewBase = nullptr;
5718 int32_t NewOffset = *Offset;
5719
5720 if (Var0 == nullptr && Const0 == nullptr) {
5721 assert(llvm::isa<ConstantRelocatable>(Src0));
5722 return false;
5723 }
5724
5725 if (Var1 == nullptr && Const1 == nullptr) {
5726 assert(llvm::isa<ConstantRelocatable>(Src1));
5727 return false;
5728 }
5729
5730 if (Var0 && Var1)
5731 // TODO(jpp): merge base/index splitting into here.
5732 return false;
5733 if (!IsAdd && Var1)
5734 return false;
5735 if (Var0)
5736 NewBase = Var0;
5737 else if (Var1)
5738 NewBase = Var1;
5739 // Compute the updated constant offset.
5740 if (Const0) {
5741 int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue();
5742 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5743 return false;
5744 NewOffset += MoreOffset;
5745 }
5746 if (Const1) {
5747 int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue();
5748 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset))
5749 return false;
5750 NewOffset += MoreOffset;
5751 }
5752
5753 // Update the computed address parameters once we are sure optimization
5754 // is valid.
5755 *Base = NewBase;
5756 *Offset = NewOffset;
5757 *Reason = BaseInst;
5758 return true;
5759}
5760} // end of anonymous namespace
5761
John Portof5f02f72015-11-09 14:52:40 -08005762OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func,
5763 const Inst *LdSt,
5764 Operand *Base) {
5765 assert(Base != nullptr);
5766 int32_t OffsetImm = 0;
5767 Variable *OffsetReg = nullptr;
5768 int32_t OffsetRegShamt = 0;
5769 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift;
5770
5771 Func->resetCurrentNode();
5772 if (Func->isVerbose(IceV_AddrOpt)) {
5773 OstreamLocker _(Func->getContext());
5774 Ostream &Str = Func->getContext()->getStrDump();
5775 Str << "\nAddress mode formation:\t";
5776 LdSt->dumpDecorated(Func);
5777 }
5778
5779 if (isVectorType(Ty))
5780 // vector loads and stores do not allow offsets, and only support the
5781 // "[reg]" addressing mode (the other supported modes are write back.)
5782 return nullptr;
5783
5784 auto *BaseVar = llvm::dyn_cast<Variable>(Base);
5785 if (BaseVar == nullptr)
5786 return nullptr;
5787
5788 (void)MemTraitsSize;
5789 assert(Ty < MemTraitsSize);
5790 auto *TypeTraits = &MemTraits[Ty];
John Porto52b51572015-12-05 14:16:25 -08005791 const bool CanHaveIndex = !NeedSandboxing && TypeTraits->CanHaveIndex;
5792 const bool CanHaveShiftedIndex =
5793 !NeedSandboxing && TypeTraits->CanHaveShiftedIndex;
John Portof5f02f72015-11-09 14:52:40 -08005794 const bool CanHaveImm = TypeTraits->CanHaveImm;
5795 const int32_t ValidImmMask = TypeTraits->ValidImmMask;
5796 (void)ValidImmMask;
5797 assert(!CanHaveImm || ValidImmMask >= 0);
5798
5799 const VariablesMetadata *VMetadata = Func->getVMetadata();
5800 const Inst *Reason = nullptr;
5801
5802 do {
5803 if (Reason != nullptr) {
5804 dumpAddressOpt(Func, BaseVar, OffsetImm, OffsetReg, OffsetRegShamt,
5805 Reason);
5806 Reason = nullptr;
5807 }
5808
5809 if (matchAssign(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5810 continue;
5811 }
5812
5813 if (CanHaveIndex &&
5814 matchAssign(VMetadata, &OffsetReg, &OffsetImm, &Reason)) {
5815 continue;
5816 }
5817
5818 if (CanHaveIndex && matchCombinedBaseIndex(VMetadata, &BaseVar, &OffsetReg,
5819 OffsetRegShamt, &Reason)) {
5820 continue;
5821 }
5822
5823 if (CanHaveShiftedIndex) {
5824 if (matchShiftedOffsetReg(VMetadata, &OffsetReg, &ShiftKind,
5825 &OffsetRegShamt, &Reason)) {
5826 continue;
5827 }
5828
5829 if ((OffsetRegShamt == 0) &&
5830 matchShiftedOffsetReg(VMetadata, &BaseVar, &ShiftKind,
5831 &OffsetRegShamt, &Reason)) {
5832 std::swap(BaseVar, OffsetReg);
5833 continue;
5834 }
5835 }
5836
5837 if (matchOffsetBase(VMetadata, &BaseVar, &OffsetImm, &Reason)) {
5838 continue;
5839 }
5840 } while (Reason);
5841
5842 if (BaseVar == nullptr) {
5843 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] is not legal in ARM, so we have to
5844 // legalize the addressing mode to [BaseReg, OffsetReg{, LSL Shamt}].
5845 // Instead of a zeroed BaseReg, we initialize it with OffsetImm:
5846 //
5847 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] ->
5848 // mov BaseReg, #OffsetImm
5849 // use of [BaseReg, OffsetReg{, LSL Shamt}]
5850 //
5851 const Type PointerType = getPointerType();
5852 BaseVar = makeReg(PointerType);
John Porto1d937a82015-12-17 06:19:34 -08005853 Context.insert<InstAssign>(BaseVar, Ctx->getConstantInt32(OffsetImm));
John Portof5f02f72015-11-09 14:52:40 -08005854 OffsetImm = 0;
5855 } else if (OffsetImm != 0) {
5856 // ARM Ldr/Str instructions have limited range immediates. The formation
5857 // loop above materialized an Immediate carelessly, so we ensure the
5858 // generated offset is sane.
5859 const int32_t PositiveOffset = OffsetImm > 0 ? OffsetImm : -OffsetImm;
5860 const InstArithmetic::OpKind Op =
5861 OffsetImm > 0 ? InstArithmetic::Add : InstArithmetic::Sub;
5862
5863 if (!CanHaveImm || !isLegalMemOffset(Ty, OffsetImm) ||
5864 OffsetReg != nullptr) {
5865 if (OffsetReg == nullptr) {
5866 // We formed a [Base, #const] addressing mode which is not encodable in
5867 // ARM. There is little point in forming an address mode now if we don't
5868 // have an offset. Effectively, we would end up with something like
5869 //
5870 // [Base, #const] -> add T, Base, #const
5871 // use of [T]
5872 //
5873 // Which is exactly what we already have. So we just bite the bullet
5874 // here and don't form any address mode.
5875 return nullptr;
5876 }
5877 // We formed [Base, Offset {, LSL Amnt}, #const]. Oops. Legalize it to
5878 //
5879 // [Base, Offset, {LSL amount}, #const] ->
5880 // add T, Base, #const
5881 // use of [T, Offset {, LSL amount}]
5882 const Type PointerType = getPointerType();
5883 Variable *T = makeReg(PointerType);
John Porto1d937a82015-12-17 06:19:34 -08005884 Context.insert<InstArithmetic>(Op, T, BaseVar,
5885 Ctx->getConstantInt32(PositiveOffset));
John Portof5f02f72015-11-09 14:52:40 -08005886 BaseVar = T;
5887 OffsetImm = 0;
5888 }
5889 }
5890
5891 assert(BaseVar != nullptr);
5892 assert(OffsetImm == 0 || OffsetReg == nullptr);
5893 assert(OffsetReg == nullptr || CanHaveIndex);
5894 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm
5895 : (ValidImmMask & OffsetImm) == OffsetImm);
5896
5897 if (OffsetReg != nullptr) {
John Porto614140e2015-11-23 11:43:13 -08005898 Variable *OffsetR = makeReg(getPointerType());
John Porto1d937a82015-12-17 06:19:34 -08005899 Context.insert<InstAssign>(OffsetR, OffsetReg);
John Porto866b6b12015-12-03 09:45:31 -08005900 return OperandARM32Mem::create(Func, Ty, BaseVar, OffsetR, ShiftKind,
John Portof5f02f72015-11-09 14:52:40 -08005901 OffsetRegShamt);
5902 }
5903
5904 return OperandARM32Mem::create(
John Porto866b6b12015-12-03 09:45:31 -08005905 Func, Ty, BaseVar,
John Portof5f02f72015-11-09 14:52:40 -08005906 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm)));
5907}
5908
5909void TargetARM32::doAddressOptLoad() {
Jim Stichnothf5fdd232016-05-09 12:24:36 -07005910 Inst *Instr = iteratorToInst(Context.getCur());
John Portof5f02f72015-11-09 14:52:40 -08005911 assert(llvm::isa<InstLoad>(Instr));
5912 Variable *Dest = Instr->getDest();
5913 Operand *Addr = Instr->getSrc(0);
5914 if (OperandARM32Mem *Mem =
5915 formAddressingMode(Dest->getType(), Func, Instr, Addr)) {
5916 Instr->setDeleted();
John Porto1d937a82015-12-17 06:19:34 -08005917 Context.insert<InstLoad>(Dest, Mem);
John Portof5f02f72015-11-09 14:52:40 -08005918 }
5919}
Jan Voungb36ad9b2015-04-21 17:01:49 -07005920
Qining Luaee5fa82015-08-20 14:59:03 -07005921void TargetARM32::randomlyInsertNop(float Probability,
5922 RandomNumberGenerator &RNG) {
5923 RandomNumberGeneratorWrapper RNGW(RNG);
5924 if (RNGW.getTrueWithProbability(Probability)) {
Karl Schimpff084a572016-02-09 13:09:23 -08005925 _nop();
Jan Voungb36ad9b2015-04-21 17:01:49 -07005926 }
5927}
5928
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08005929void TargetARM32::lowerPhi(const InstPhi * /*Instr*/) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07005930 Func->setError("Phi found in regular instruction list");
5931}
5932
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08005933void TargetARM32::lowerRet(const InstRet *Instr) {
Jan Voungb2d50842015-05-12 09:53:50 -07005934 Variable *Reg = nullptr;
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08005935 if (Instr->hasRetValue()) {
5936 Operand *Src0 = Instr->getRetValue();
Jan Voung86ebec12015-08-09 07:58:35 -07005937 Type Ty = Src0->getType();
5938 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07005939 Src0 = legalizeUndef(Src0);
Andrew Scull97f460d2015-07-21 10:07:42 -07005940 Variable *R0 = legalizeToReg(loOperand(Src0), RegARM32::Reg_r0);
5941 Variable *R1 = legalizeToReg(hiOperand(Src0), RegARM32::Reg_r1);
Jan Voungb3401d22015-05-18 09:38:21 -07005942 Reg = R0;
John Porto1d937a82015-12-17 06:19:34 -08005943 Context.insert<InstFakeUse>(R1);
Jan Voung86ebec12015-08-09 07:58:35 -07005944 } else if (Ty == IceType_f32) {
5945 Variable *S0 = legalizeToReg(Src0, RegARM32::Reg_s0);
5946 Reg = S0;
5947 } else if (Ty == IceType_f64) {
5948 Variable *D0 = legalizeToReg(Src0, RegARM32::Reg_d0);
5949 Reg = D0;
Jan Voungb3401d22015-05-18 09:38:21 -07005950 } else if (isVectorType(Src0->getType())) {
Jan Voung86ebec12015-08-09 07:58:35 -07005951 Variable *Q0 = legalizeToReg(Src0, RegARM32::Reg_q0);
5952 Reg = Q0;
Jan Voungb3401d22015-05-18 09:38:21 -07005953 } else {
5954 Operand *Src0F = legalize(Src0, Legal_Reg | Legal_Flex);
John Portoba6a67c2015-09-25 15:19:45 -07005955 Reg = makeReg(Src0F->getType(), RegARM32::Reg_r0);
5956 _mov(Reg, Src0F, CondARM32::AL);
Jan Voungb3401d22015-05-18 09:38:21 -07005957 }
Jan Voungb2d50842015-05-12 09:53:50 -07005958 }
Andrew Scull57e12682015-09-16 11:30:19 -07005959 // Add a ret instruction even if sandboxing is enabled, because addEpilog
5960 // explicitly looks for a ret instruction as a marker for where to insert the
5961 // frame removal instructions. addEpilog is responsible for restoring the
5962 // "lr" register as needed prior to this ret instruction.
Jan Voungb2d50842015-05-12 09:53:50 -07005963 _ret(getPhysicalRegister(RegARM32::Reg_lr), Reg);
John Porto52b51572015-12-05 14:16:25 -08005964
Andrew Scull57e12682015-09-16 11:30:19 -07005965 // Add a fake use of sp to make sure sp stays alive for the entire function.
5966 // Otherwise post-call sp adjustments get dead-code eliminated.
5967 // TODO: Are there more places where the fake use should be inserted? E.g.
5968 // "void f(int n){while(1) g(n);}" may not have a ret instruction.
Jan Voungf645d852015-07-09 10:35:09 -07005969 Variable *SP = getPhysicalRegister(RegARM32::Reg_sp);
John Porto1d937a82015-12-17 06:19:34 -08005970 Context.insert<InstFakeUse>(SP);
Jan Voungb36ad9b2015-04-21 17:01:49 -07005971}
5972
John Portoa47c11c2016-04-21 05:53:42 -07005973void TargetARM32::lowerShuffleVector(const InstShuffleVector *Instr) {
5974 auto *Dest = Instr->getDest();
5975 const Type DestTy = Dest->getType();
5976
5977 auto *T = makeReg(DestTy);
Nicolas Capensf6951fa2017-10-02 10:44:03 -04005978 auto *Src0 = Instr->getSrc(0);
5979 auto *Src1 = Instr->getSrc(1);
5980 const SizeT NumElements = typeNumElements(DestTy);
5981 const Type ElementType = typeElementType(DestTy);
5982
5983 bool Replicate = true;
5984 for (SizeT I = 1; Replicate && I < Instr->getNumIndexes(); ++I) {
5985 if (Instr->getIndexValue(I) != Instr->getIndexValue(0)) {
5986 Replicate = false;
5987 }
5988 }
5989
5990 if (Replicate) {
5991 Variable *Src0Var = legalizeToReg(Src0);
5992 _vdup(T, Src0Var, Instr->getIndexValue(0));
5993 _mov(Dest, T);
5994 return;
5995 }
John Portoa47c11c2016-04-21 05:53:42 -07005996
5997 switch (DestTy) {
Nicolas Capensf6951fa2017-10-02 10:44:03 -04005998 case IceType_v8i1:
5999 case IceType_v8i16: {
6000 static constexpr SizeT ExpectedNumElements = 8;
6001 assert(ExpectedNumElements == Instr->getNumIndexes());
6002 (void)ExpectedNumElements;
6003
6004 if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3)) {
6005 Variable *Src0R = legalizeToReg(Src0);
6006 _vzip(T, Src0R, Src0R);
6007 _mov(Dest, T);
6008 return;
6009 }
6010
6011 if (Instr->indexesAre(0, 8, 1, 9, 2, 10, 3, 11)) {
6012 Variable *Src0R = legalizeToReg(Src0);
6013 Variable *Src1R = legalizeToReg(Src1);
6014 _vzip(T, Src0R, Src1R);
6015 _mov(Dest, T);
6016 return;
6017 }
6018
6019 if (Instr->indexesAre(0, 2, 4, 6, 0, 2, 4, 6)) {
6020 Variable *Src0R = legalizeToReg(Src0);
6021 _vqmovn2(T, Src0R, Src0R, false, false);
6022 _mov(Dest, T);
6023 return;
6024 }
6025 } break;
6026 case IceType_v16i1:
6027 case IceType_v16i8: {
6028 static constexpr SizeT ExpectedNumElements = 16;
6029 assert(ExpectedNumElements == Instr->getNumIndexes());
6030 (void)ExpectedNumElements;
6031
6032 if (Instr->indexesAre(0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7)) {
6033 Variable *Src0R = legalizeToReg(Src0);
6034 _vzip(T, Src0R, Src0R);
6035 _mov(Dest, T);
6036 return;
6037 }
6038
6039 if (Instr->indexesAre(0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7,
6040 23)) {
6041 Variable *Src0R = legalizeToReg(Src0);
6042 Variable *Src1R = legalizeToReg(Src1);
6043 _vzip(T, Src0R, Src1R);
6044 _mov(Dest, T);
6045 return;
6046 }
6047 } break;
6048 case IceType_v4i1:
6049 case IceType_v4i32:
6050 case IceType_v4f32: {
6051 static constexpr SizeT ExpectedNumElements = 4;
6052 assert(ExpectedNumElements == Instr->getNumIndexes());
6053 (void)ExpectedNumElements;
6054
6055 if (Instr->indexesAre(0, 0, 1, 1)) {
6056 Variable *Src0R = legalizeToReg(Src0);
6057 _vzip(T, Src0R, Src0R);
6058 _mov(Dest, T);
6059 return;
6060 }
6061
6062 if (Instr->indexesAre(0, 4, 1, 5)) {
6063 Variable *Src0R = legalizeToReg(Src0);
6064 Variable *Src1R = legalizeToReg(Src1);
6065 _vzip(T, Src0R, Src1R);
6066 _mov(Dest, T);
6067 return;
6068 }
6069
6070 if (Instr->indexesAre(0, 1, 4, 5)) {
6071 Variable *Src0R = legalizeToReg(Src0);
6072 Variable *Src1R = legalizeToReg(Src1);
6073 _vmovlh(T, Src0R, Src1R);
6074 _mov(Dest, T);
6075 return;
6076 }
6077
6078 if (Instr->indexesAre(2, 3, 2, 3)) {
6079 Variable *Src0R = legalizeToReg(Src0);
6080 _vmovhl(T, Src0R, Src0R);
6081 _mov(Dest, T);
6082 return;
6083 }
6084
6085 if (Instr->indexesAre(2, 3, 6, 7)) {
6086 Variable *Src0R = legalizeToReg(Src0);
6087 Variable *Src1R = legalizeToReg(Src1);
6088 _vmovhl(T, Src1R, Src0R);
6089 _mov(Dest, T);
6090 return;
6091 }
6092 } break;
John Portoa47c11c2016-04-21 05:53:42 -07006093 default:
6094 break;
6095 // TODO(jpp): figure out how to properly lower this without scalarization.
6096 }
6097
6098 // Unoptimized shuffle. Perform a series of inserts and extracts.
6099 Context.insert<InstFakeDef>(T);
John Portoa47c11c2016-04-21 05:53:42 -07006100 for (SizeT I = 0; I < Instr->getNumIndexes(); ++I) {
6101 auto *Index = Instr->getIndex(I);
6102 const SizeT Elem = Index->getValue();
6103 auto *ExtElmt = makeReg(ElementType);
6104 if (Elem < NumElements) {
6105 lowerExtractElement(
6106 InstExtractElement::create(Func, ExtElmt, Src0, Index));
6107 } else {
6108 lowerExtractElement(InstExtractElement::create(
6109 Func, ExtElmt, Src1,
6110 Ctx->getConstantInt32(Index->getValue() - NumElements)));
6111 }
6112 auto *NewT = makeReg(DestTy);
6113 lowerInsertElement(InstInsertElement::create(Func, NewT, T, ExtElmt,
6114 Ctx->getConstantInt32(I)));
6115 T = NewT;
6116 }
6117 _mov(Dest, T);
6118}
6119
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006120void TargetARM32::lowerSelect(const InstSelect *Instr) {
6121 Variable *Dest = Instr->getDest();
Jan Vounge0df91f2015-06-30 08:47:06 -07006122 Type DestTy = Dest->getType();
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006123 Operand *SrcT = Instr->getTrueOperand();
6124 Operand *SrcF = Instr->getFalseOperand();
6125 Operand *Condition = Instr->getCondition();
Jan Vounge0df91f2015-06-30 08:47:06 -07006126
John Porto397f6022016-04-15 06:26:58 -07006127 if (!isVectorType(DestTy)) {
6128 lowerInt1ForSelect(Dest, Condition, legalizeUndef(SrcT),
6129 legalizeUndef(SrcF));
Jan Vounge0df91f2015-06-30 08:47:06 -07006130 return;
6131 }
John Porto4a5e6d02015-11-04 09:32:55 -08006132
John Porto397f6022016-04-15 06:26:58 -07006133 Type TType = DestTy;
6134 switch (DestTy) {
6135 default:
6136 llvm::report_fatal_error("Unexpected type for vector select.");
6137 case IceType_v4i1:
6138 TType = IceType_v4i32;
6139 break;
6140 case IceType_v8i1:
6141 TType = IceType_v8i16;
6142 break;
6143 case IceType_v16i1:
6144 TType = IceType_v16i8;
6145 break;
6146 case IceType_v4f32:
6147 TType = IceType_v4i32;
6148 break;
6149 case IceType_v4i32:
6150 case IceType_v8i16:
6151 case IceType_v16i8:
6152 break;
6153 }
6154 auto *T = makeReg(TType);
6155 lowerCast(InstCast::create(Func, InstCast::Sext, T, Condition));
6156 auto *SrcTR = legalizeToReg(SrcT);
6157 auto *SrcFR = legalizeToReg(SrcF);
6158 _vbsl(T, SrcTR, SrcFR)->setDestRedefined();
6159 _mov(Dest, T);
Jan Voungb36ad9b2015-04-21 17:01:49 -07006160}
6161
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006162void TargetARM32::lowerStore(const InstStore *Instr) {
6163 Operand *Value = Instr->getData();
6164 Operand *Addr = Instr->getAddr();
Jan Voungbefd03a2015-06-02 11:03:03 -07006165 OperandARM32Mem *NewAddr = formMemoryOperand(Addr, Value->getType());
6166 Type Ty = NewAddr->getType();
6167
6168 if (Ty == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006169 Value = legalizeUndef(Value);
Andrew Scull97f460d2015-07-21 10:07:42 -07006170 Variable *ValueHi = legalizeToReg(hiOperand(Value));
6171 Variable *ValueLo = legalizeToReg(loOperand(Value));
Jan Voungbefd03a2015-06-02 11:03:03 -07006172 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr)));
6173 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr)));
Jan Voungbefd03a2015-06-02 11:03:03 -07006174 } else {
Andrew Scull97f460d2015-07-21 10:07:42 -07006175 Variable *ValueR = legalizeToReg(Value);
Jan Voungbefd03a2015-06-02 11:03:03 -07006176 _str(ValueR, NewAddr);
6177 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07006178}
6179
John Portof5f02f72015-11-09 14:52:40 -08006180void TargetARM32::doAddressOptStore() {
Jim Stichnothf5fdd232016-05-09 12:24:36 -07006181 Inst *Instr = iteratorToInst(Context.getCur());
John Portof5f02f72015-11-09 14:52:40 -08006182 assert(llvm::isa<InstStore>(Instr));
6183 Operand *Src = Instr->getSrc(0);
6184 Operand *Addr = Instr->getSrc(1);
6185 if (OperandARM32Mem *Mem =
6186 formAddressingMode(Src->getType(), Func, Instr, Addr)) {
6187 Instr->setDeleted();
John Porto1d937a82015-12-17 06:19:34 -08006188 Context.insert<InstStore>(Src, Mem);
John Portof5f02f72015-11-09 14:52:40 -08006189 }
6190}
Jan Voungb36ad9b2015-04-21 17:01:49 -07006191
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006192void TargetARM32::lowerSwitch(const InstSwitch *Instr) {
Andrew Scullfdc54db2015-06-29 11:21:18 -07006193 // This implements the most naive possible lowering.
6194 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006195 Operand *Src0 = Instr->getComparison();
6196 SizeT NumCases = Instr->getNumCases();
Andrew Scullfdc54db2015-06-29 11:21:18 -07006197 if (Src0->getType() == IceType_i64) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006198 Src0 = legalizeUndef(Src0);
Andrew Scull97f460d2015-07-21 10:07:42 -07006199 Variable *Src0Lo = legalizeToReg(loOperand(Src0));
6200 Variable *Src0Hi = legalizeToReg(hiOperand(Src0));
Andrew Scullfdc54db2015-06-29 11:21:18 -07006201 for (SizeT I = 0; I < NumCases; ++I) {
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006202 Operand *ValueLo = Ctx->getConstantInt32(Instr->getValue(I));
6203 Operand *ValueHi = Ctx->getConstantInt32(Instr->getValue(I) >> 32);
Andrew Scullfdc54db2015-06-29 11:21:18 -07006204 ValueLo = legalize(ValueLo, Legal_Reg | Legal_Flex);
6205 ValueHi = legalize(ValueHi, Legal_Reg | Legal_Flex);
6206 _cmp(Src0Lo, ValueLo);
6207 _cmp(Src0Hi, ValueHi, CondARM32::EQ);
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006208 _br(Instr->getLabel(I), CondARM32::EQ);
Andrew Scullfdc54db2015-06-29 11:21:18 -07006209 }
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006210 _br(Instr->getLabelDefault());
Andrew Scullfdc54db2015-06-29 11:21:18 -07006211 return;
6212 }
Jan Vounge0df91f2015-06-30 08:47:06 -07006213
Andrew Scull97f460d2015-07-21 10:07:42 -07006214 Variable *Src0Var = legalizeToReg(Src0);
John Portoafc92af2015-10-16 10:34:04 -07006215 // If Src0 is not an i32, we left shift it -- see the icmp lowering for the
6216 // reason.
6217 assert(Src0Var->mustHaveReg());
6218 const size_t ShiftAmt = 32 - getScalarIntBitWidth(Src0->getType());
6219 assert(ShiftAmt < 32);
6220 if (ShiftAmt > 0) {
John Porto2758bb02015-11-17 14:31:25 -08006221 Operand *ShAmtImm = shAmtImm(ShiftAmt);
John Portoafc92af2015-10-16 10:34:04 -07006222 Variable *T = makeReg(IceType_i32);
John Porto2758bb02015-11-17 14:31:25 -08006223 _lsl(T, Src0Var, ShAmtImm);
John Portoafc92af2015-10-16 10:34:04 -07006224 Src0Var = T;
6225 }
6226
Andrew Scullfdc54db2015-06-29 11:21:18 -07006227 for (SizeT I = 0; I < NumCases; ++I) {
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006228 Operand *Value = Ctx->getConstantInt32(Instr->getValue(I) << ShiftAmt);
Andrew Scullfdc54db2015-06-29 11:21:18 -07006229 Value = legalize(Value, Legal_Reg | Legal_Flex);
6230 _cmp(Src0Var, Value);
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006231 _br(Instr->getLabel(I), CondARM32::EQ);
Andrew Scullfdc54db2015-06-29 11:21:18 -07006232 }
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006233 _br(Instr->getLabelDefault());
Jan Voungb36ad9b2015-04-21 17:01:49 -07006234}
6235
Eric Holk67c7c412016-04-15 13:05:37 -07006236void TargetARM32::lowerBreakpoint(const InstBreakpoint *Instr) {
6237 UnimplementedLoweringError(this, Instr);
6238}
6239
Jim Stichnoth8cfeb692016-02-05 09:50:02 -08006240void TargetARM32::lowerUnreachable(const InstUnreachable * /*Instr*/) {
Jan Voung6ec369e2015-06-30 11:03:15 -07006241 _trap();
Jan Voungb36ad9b2015-04-21 17:01:49 -07006242}
6243
John Portodc619252016-02-10 15:57:16 -08006244namespace {
6245// Returns whether Opnd needs the GOT address. Currently, ConstantRelocatables,
6246// and fp constants will need access to the GOT address.
6247bool operandNeedsGot(const Operand *Opnd) {
6248 if (llvm::isa<ConstantRelocatable>(Opnd)) {
6249 return true;
6250 }
6251
6252 if (llvm::isa<ConstantFloat>(Opnd)) {
6253 uint32_t _;
6254 return !OperandARM32FlexFpImm::canHoldImm(Opnd, &_);
6255 }
6256
6257 const auto *F64 = llvm::dyn_cast<ConstantDouble>(Opnd);
6258 if (F64 != nullptr) {
6259 uint32_t _;
6260 return !OperandARM32FlexFpImm::canHoldImm(Opnd, &_) &&
6261 !isFloatingPointZero(F64);
6262 }
6263
6264 return false;
6265}
6266
6267// Returns whether Phi needs the GOT address (which it does if any of its
6268// operands needs the GOT address.)
6269bool phiNeedsGot(const InstPhi *Phi) {
6270 if (Phi->isDeleted()) {
6271 return false;
6272 }
6273
6274 for (SizeT I = 0; I < Phi->getSrcSize(); ++I) {
6275 if (operandNeedsGot(Phi->getSrc(I))) {
6276 return true;
6277 }
6278 }
6279
6280 return false;
6281}
6282
6283// Returns whether **any** phi in Node needs the GOT address.
6284bool anyPhiInNodeNeedsGot(CfgNode *Node) {
6285 for (auto &Inst : Node->getPhis()) {
6286 if (phiNeedsGot(llvm::cast<InstPhi>(&Inst))) {
6287 return true;
6288 }
6289 }
6290 return false;
6291}
6292
6293} // end of anonymous namespace
6294
Jan Voungb36ad9b2015-04-21 17:01:49 -07006295void TargetARM32::prelowerPhis() {
John Portodc619252016-02-10 15:57:16 -08006296 CfgNode *Node = Context.getNode();
6297
6298 if (SandboxingType == ST_Nonsfi) {
6299 assert(GotPtr != nullptr);
6300 if (anyPhiInNodeNeedsGot(Node)) {
6301 // If any phi instruction needs the GOT address, we place a
6302 // fake-use GotPtr
6303 // in Node to prevent the GotPtr's initialization from being dead code
6304 // eliminated.
6305 Node->getInsts().push_front(InstFakeUse::create(Func, GotPtr));
6306 }
6307 }
6308
6309 PhiLowering::prelowerPhis32Bit(this, Node, Func);
Jan Voungb36ad9b2015-04-21 17:01:49 -07006310}
6311
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006312Variable *TargetARM32::makeVectorOfZeros(Type Ty, RegNumT RegNum) {
Jan Voungb3401d22015-05-18 09:38:21 -07006313 Variable *Reg = makeReg(Ty, RegNum);
John Porto1d937a82015-12-17 06:19:34 -08006314 Context.insert<InstFakeDef>(Reg);
Eric Holkcfc25532016-02-09 17:47:58 -08006315 assert(isVectorType(Ty));
6316 _veor(Reg, Reg, Reg);
Jan Voungb3401d22015-05-18 09:38:21 -07006317 return Reg;
6318}
6319
6320// Helper for legalize() to emit the right code to lower an operand to a
6321// register of the appropriate type.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006322Variable *TargetARM32::copyToReg(Operand *Src, RegNumT RegNum) {
Jan Voungb3401d22015-05-18 09:38:21 -07006323 Type Ty = Src->getType();
6324 Variable *Reg = makeReg(Ty, RegNum);
John Porto3f6b47d2015-11-19 05:42:59 -08006325 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Src)) {
6326 _ldr(Reg, Mem);
6327 } else {
6328 _mov(Reg, Src);
6329 }
Jan Voungb3401d22015-05-18 09:38:21 -07006330 return Reg;
6331}
6332
John Portoeb13acc2015-12-09 05:10:58 -08006333// TODO(jpp): remove unneeded else clauses in legalize.
Jan Voungb3401d22015-05-18 09:38:21 -07006334Operand *TargetARM32::legalize(Operand *From, LegalMask Allowed,
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006335 RegNumT RegNum) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006336 Type Ty = From->getType();
Andrew Scull57e12682015-09-16 11:30:19 -07006337 // Assert that a physical register is allowed. To date, all calls to
6338 // legalize() allow a physical register. Legal_Flex converts registers to the
6339 // right type OperandARM32FlexReg as needed.
Jan Voungb3401d22015-05-18 09:38:21 -07006340 assert(Allowed & Legal_Reg);
John Porto562233c2015-10-28 05:47:58 -07006341
6342 // Copied ipsis literis from TargetX86Base<Machine>.
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006343 if (RegNum.hasNoValue()) {
John Porto562233c2015-10-28 05:47:58 -07006344 if (Variable *Subst = getContext().availabilityGet(From)) {
6345 // At this point we know there is a potential substitution available.
John Porto614140e2015-11-23 11:43:13 -08006346 if (!Subst->isRematerializable() && Subst->mustHaveReg() &&
6347 !Subst->hasReg()) {
John Porto562233c2015-10-28 05:47:58 -07006348 // At this point we know the substitution will have a register.
6349 if (From->getType() == Subst->getType()) {
6350 // At this point we know the substitution's register is compatible.
6351 return Subst;
6352 }
6353 }
6354 }
6355 }
6356
Andrew Scull57e12682015-09-16 11:30:19 -07006357 // Go through the various types of operands: OperandARM32Mem,
6358 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if
6359 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we
6360 // can always copy to a register.
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07006361 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) {
Andrew Scull57e12682015-09-16 11:30:19 -07006362 // Before doing anything with a Mem operand, we need to ensure that the
6363 // Base and Index components are in physical registers.
Jan Voungb3401d22015-05-18 09:38:21 -07006364 Variable *Base = Mem->getBase();
6365 Variable *Index = Mem->getIndex();
John Portoba6a67c2015-09-25 15:19:45 -07006366 ConstantInteger32 *Offset = Mem->getOffset();
6367 assert(Index == nullptr || Offset == nullptr);
Jan Voungb3401d22015-05-18 09:38:21 -07006368 Variable *RegBase = nullptr;
6369 Variable *RegIndex = nullptr;
John Portof5f02f72015-11-09 14:52:40 -08006370 assert(Base);
John Porto866b6b12015-12-03 09:45:31 -08006371 RegBase = llvm::cast<Variable>(
6372 legalize(Base, Legal_Reg | Legal_Rematerializable));
John Portof5f02f72015-11-09 14:52:40 -08006373 assert(Ty < MemTraitsSize);
Jan Voungb3401d22015-05-18 09:38:21 -07006374 if (Index) {
John Portof5f02f72015-11-09 14:52:40 -08006375 assert(Offset == nullptr);
6376 assert(MemTraits[Ty].CanHaveIndex);
Andrew Scull97f460d2015-07-21 10:07:42 -07006377 RegIndex = legalizeToReg(Index);
Jan Voungb3401d22015-05-18 09:38:21 -07006378 }
John Portoba6a67c2015-09-25 15:19:45 -07006379 if (Offset && Offset->getValue() != 0) {
John Portof5f02f72015-11-09 14:52:40 -08006380 assert(Index == nullptr);
6381 static constexpr bool ZeroExt = false;
6382 assert(MemTraits[Ty].CanHaveImm);
6383 if (!OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) {
John Porto3f6b47d2015-11-19 05:42:59 -08006384 llvm::report_fatal_error("Invalid memory offset.");
John Portoba6a67c2015-09-25 15:19:45 -07006385 }
6386 }
6387
Jan Voungb3401d22015-05-18 09:38:21 -07006388 // Create a new operand if there was a change.
6389 if (Base != RegBase || Index != RegIndex) {
6390 // There is only a reg +/- reg or reg + imm form.
6391 // Figure out which to re-create.
John Portof5f02f72015-11-09 14:52:40 -08006392 if (RegIndex) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006393 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex,
Jan Voungb3401d22015-05-18 09:38:21 -07006394 Mem->getShiftOp(), Mem->getShiftAmt(),
6395 Mem->getAddrMode());
6396 } else {
John Portoba6a67c2015-09-25 15:19:45 -07006397 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset,
Jan Voungfbdd2442015-07-15 12:36:20 -07006398 Mem->getAddrMode());
Jan Voungb3401d22015-05-18 09:38:21 -07006399 }
6400 }
John Portoba6a67c2015-09-25 15:19:45 -07006401 if (Allowed & Legal_Mem) {
Jan Voungb3401d22015-05-18 09:38:21 -07006402 From = Mem;
John Portoba6a67c2015-09-25 15:19:45 -07006403 } else {
6404 Variable *Reg = makeReg(Ty, RegNum);
John Porto3f6b47d2015-11-19 05:42:59 -08006405 _ldr(Reg, Mem);
John Portoba6a67c2015-09-25 15:19:45 -07006406 From = Reg;
Jan Voungb3401d22015-05-18 09:38:21 -07006407 }
6408 return From;
6409 }
6410
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07006411 if (auto *Flex = llvm::dyn_cast<OperandARM32Flex>(From)) {
Jan Voungb3401d22015-05-18 09:38:21 -07006412 if (!(Allowed & Legal_Flex)) {
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07006413 if (auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) {
Jan Voungb3401d22015-05-18 09:38:21 -07006414 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) {
6415 From = FlexReg->getReg();
Andrew Scull57e12682015-09-16 11:30:19 -07006416 // Fall through and let From be checked as a Variable below, where it
6417 // may or may not need a register.
Jan Voungb3401d22015-05-18 09:38:21 -07006418 } else {
6419 return copyToReg(Flex, RegNum);
6420 }
6421 } else {
6422 return copyToReg(Flex, RegNum);
6423 }
6424 } else {
6425 return From;
6426 }
6427 }
6428
6429 if (llvm::isa<Constant>(From)) {
6430 if (llvm::isa<ConstantUndef>(From)) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006431 From = legalizeUndef(From, RegNum);
6432 if (isVectorType(Ty))
6433 return From;
Jan Voungb3401d22015-05-18 09:38:21 -07006434 }
6435 // There should be no constants of vector type (other than undef).
Jan Voungfbdd2442015-07-15 12:36:20 -07006436 assert(!isVectorType(Ty));
Jan Voungfbdd2442015-07-15 12:36:20 -07006437 if (auto *C32 = llvm::dyn_cast<ConstantInteger32>(From)) {
Jan Voungb3401d22015-05-18 09:38:21 -07006438 uint32_t RotateAmt;
6439 uint32_t Immed_8;
6440 uint32_t Value = static_cast<uint32_t>(C32->getValue());
John Portoeb13acc2015-12-09 05:10:58 -08006441 if (OperandARM32FlexImm::canHoldImm(Value, &RotateAmt, &Immed_8)) {
6442 // The immediate can be encoded as a Flex immediate. We may return the
6443 // Flex operand if the caller has Allow'ed it.
6444 auto *OpF = OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
6445 const bool CanBeFlex = Allowed & Legal_Flex;
6446 if (CanBeFlex)
6447 return OpF;
6448 return copyToReg(OpF, RegNum);
6449 } else if (OperandARM32FlexImm::canHoldImm(~Value, &RotateAmt,
6450 &Immed_8)) {
6451 // Even though the immediate can't be encoded as a Flex operand, its
6452 // inverted bit pattern can, thus we use ARM's mvn to load the 32-bit
6453 // constant with a single instruction.
6454 auto *InvOpF =
Jan Voungfbdd2442015-07-15 12:36:20 -07006455 OperandARM32FlexImm::create(Func, Ty, Immed_8, RotateAmt);
Jan Voungb3401d22015-05-18 09:38:21 -07006456 Variable *Reg = makeReg(Ty, RegNum);
John Portoeb13acc2015-12-09 05:10:58 -08006457 _mvn(Reg, InvOpF);
Jan Voungb3401d22015-05-18 09:38:21 -07006458 return Reg;
6459 } else {
6460 // Do a movw/movt to a register.
Jan Voungb3401d22015-05-18 09:38:21 -07006461 Variable *Reg = makeReg(Ty, RegNum);
6462 uint32_t UpperBits = (Value >> 16) & 0xFFFF;
6463 _movw(Reg,
6464 UpperBits != 0 ? Ctx->getConstantInt32(Value & 0xFFFF) : C32);
6465 if (UpperBits != 0) {
6466 _movt(Reg, Ctx->getConstantInt32(UpperBits));
6467 }
6468 return Reg;
6469 }
Jan Voungfbdd2442015-07-15 12:36:20 -07006470 } else if (auto *C = llvm::dyn_cast<ConstantRelocatable>(From)) {
Jan Voungb3401d22015-05-18 09:38:21 -07006471 Variable *Reg = makeReg(Ty, RegNum);
John Portodc619252016-02-10 15:57:16 -08006472 if (SandboxingType != ST_Nonsfi) {
6473 _movw(Reg, C);
6474 _movt(Reg, C);
6475 } else {
6476 auto *GotAddr = legalizeToReg(GotPtr);
Jim Stichnoth467ffe52016-03-29 15:01:06 -07006477 GlobalString CGotoffName = createGotoffRelocation(C);
John Portodc619252016-02-10 15:57:16 -08006478 loadNamedConstantRelocatablePIC(
6479 CGotoffName, Reg, [this, Reg](Variable *PC) {
6480 _ldr(Reg, OperandARM32Mem::create(Func, IceType_i32, PC, Reg));
6481 });
6482 _add(Reg, GotAddr, Reg);
6483 }
Jan Voungb3401d22015-05-18 09:38:21 -07006484 return Reg;
6485 } else {
Jan Voung86ebec12015-08-09 07:58:35 -07006486 assert(isScalarFloatingType(Ty));
John Portoccea7932015-11-17 04:58:36 -08006487 uint32_t ModifiedImm;
6488 if (OperandARM32FlexFpImm::canHoldImm(From, &ModifiedImm)) {
6489 Variable *T = makeReg(Ty, RegNum);
6490 _mov(T,
6491 OperandARM32FlexFpImm::create(Func, From->getType(), ModifiedImm));
6492 return T;
6493 }
6494
6495 if (Ty == IceType_f64 && isFloatingPointZero(From)) {
6496 // Use T = T ^ T to load a 64-bit fp zero. This does not work for f32
6497 // because ARM does not have a veor instruction with S registers.
6498 Variable *T = makeReg(IceType_f64, RegNum);
John Porto1d937a82015-12-17 06:19:34 -08006499 Context.insert<InstFakeDef>(T);
John Portoccea7932015-11-17 04:58:36 -08006500 _veor(T, T, T);
6501 return T;
6502 }
6503
Jan Voungb3401d22015-05-18 09:38:21 -07006504 // Load floats/doubles from literal pool.
Jim Stichnoth467ffe52016-03-29 15:01:06 -07006505 auto *CFrom = llvm::cast<Constant>(From);
6506 assert(CFrom->getShouldBePooled());
6507 Constant *Offset = Ctx->getConstantSym(0, CFrom->getLabelName());
John Portodc619252016-02-10 15:57:16 -08006508 Variable *BaseReg = nullptr;
6509 if (SandboxingType == ST_Nonsfi) {
6510 // vldr does not support the [base, index] addressing mode, so we need
6511 // to legalize Offset to a register. Otherwise, we could simply
6512 // vldr dest, [got, reg(Offset)]
6513 BaseReg = legalizeToReg(Offset);
6514 } else {
6515 BaseReg = makeReg(getPointerType());
6516 _movw(BaseReg, Offset);
6517 _movt(BaseReg, Offset);
6518 }
Jan Voung86ebec12015-08-09 07:58:35 -07006519 From = formMemoryOperand(BaseReg, Ty);
6520 return copyToReg(From, RegNum);
Jan Voungb3401d22015-05-18 09:38:21 -07006521 }
Jan Voungb3401d22015-05-18 09:38:21 -07006522 }
6523
Jim Stichnoth5bff61c2015-10-28 09:26:00 -07006524 if (auto *Var = llvm::dyn_cast<Variable>(From)) {
John Porto614140e2015-11-23 11:43:13 -08006525 if (Var->isRematerializable()) {
John Porto866b6b12015-12-03 09:45:31 -08006526 if (Allowed & Legal_Rematerializable) {
6527 return From;
6528 }
6529
John Porto614140e2015-11-23 11:43:13 -08006530 Variable *T = makeReg(Var->getType(), RegNum);
6531 _mov(T, Var);
6532 return T;
6533 }
Andrew Scull57e12682015-09-16 11:30:19 -07006534 // Check if the variable is guaranteed a physical register. This can happen
6535 // either when the variable is pre-colored or when it is assigned infinite
6536 // weight.
Andrew Scull11c9a322015-08-28 14:24:14 -07006537 bool MustHaveRegister = (Var->hasReg() || Var->mustHaveReg());
Jan Voungb3401d22015-05-18 09:38:21 -07006538 // We need a new physical register for the operand if:
6539 // Mem is not allowed and Var isn't guaranteed a physical
6540 // register, or
6541 // RegNum is required and Var->getRegNum() doesn't match.
6542 if ((!(Allowed & Legal_Mem) && !MustHaveRegister) ||
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006543 (RegNum.hasValue() && (RegNum != Var->getRegNum()))) {
Jan Voungb3401d22015-05-18 09:38:21 -07006544 From = copyToReg(From, RegNum);
6545 }
6546 return From;
6547 }
John Portoc39ec102015-12-01 13:00:43 -08006548 llvm::report_fatal_error("Unhandled operand kind in legalize()");
Jan Voungb3401d22015-05-18 09:38:21 -07006549
6550 return From;
6551}
6552
Jan Voungfbdd2442015-07-15 12:36:20 -07006553/// Provide a trivial wrapper to legalize() for this common usage.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006554Variable *TargetARM32::legalizeToReg(Operand *From, RegNumT RegNum) {
Jan Voungb3401d22015-05-18 09:38:21 -07006555 return llvm::cast<Variable>(legalize(From, Legal_Reg, RegNum));
6556}
6557
Jan Voungfbdd2442015-07-15 12:36:20 -07006558/// Legalize undef values to concrete values.
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006559Operand *TargetARM32::legalizeUndef(Operand *From, RegNumT RegNum) {
Jan Voungfbdd2442015-07-15 12:36:20 -07006560 Type Ty = From->getType();
6561 if (llvm::isa<ConstantUndef>(From)) {
Andrew Scull57e12682015-09-16 11:30:19 -07006562 // Lower undefs to zero. Another option is to lower undefs to an
6563 // uninitialized register; however, using an uninitialized register results
6564 // in less predictable code.
Jan Voungfbdd2442015-07-15 12:36:20 -07006565 //
Andrew Scull57e12682015-09-16 11:30:19 -07006566 // If in the future the implementation is changed to lower undef values to
6567 // uninitialized registers, a FakeDef will be needed:
6568 // Context.insert(InstFakeDef::create(Func, Reg)); This is in order to
6569 // ensure that the live range of Reg is not overestimated. If the constant
6570 // being lowered is a 64 bit value, then the result should be split and the
6571 // lo and hi components will need to go in uninitialized registers.
Jan Voungfbdd2442015-07-15 12:36:20 -07006572 if (isVectorType(Ty))
6573 return makeVectorOfZeros(Ty, RegNum);
6574 return Ctx->getConstantZero(Ty);
6575 }
6576 return From;
6577}
6578
Jan Voungbefd03a2015-06-02 11:03:03 -07006579OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) {
Jim Stichnoth54f3d512015-12-11 09:53:00 -08006580 auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand);
Andrew Scull57e12682015-09-16 11:30:19 -07006581 // It may be the case that address mode optimization already creates an
6582 // OperandARM32Mem, so in that case it wouldn't need another level of
6583 // transformation.
Jan Voungbefd03a2015-06-02 11:03:03 -07006584 if (Mem) {
6585 return llvm::cast<OperandARM32Mem>(legalize(Mem));
6586 }
John Portof5f02f72015-11-09 14:52:40 -08006587 // If we didn't do address mode optimization, then we only have a
6588 // base/offset to work with. ARM always requires a base register, so
6589 // just use that to hold the operand.
Jim Stichnoth54f3d512015-12-11 09:53:00 -08006590 auto *Base = llvm::cast<Variable>(
John Porto866b6b12015-12-03 09:45:31 -08006591 legalize(Operand, Legal_Reg | Legal_Rematerializable));
Jan Voungbefd03a2015-06-02 11:03:03 -07006592 return OperandARM32Mem::create(
John Porto866b6b12015-12-03 09:45:31 -08006593 Func, Ty, Base,
Jan Voungbefd03a2015-06-02 11:03:03 -07006594 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32)));
6595}
6596
John Porto578f1162015-10-06 06:54:42 -07006597Variable64On32 *TargetARM32::makeI64RegPair() {
6598 Variable64On32 *Reg =
6599 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64));
6600 Reg->setMustHaveReg();
6601 Reg->initHiLo(Func);
6602 Reg->getLo()->setMustNotHaveReg();
6603 Reg->getHi()->setMustNotHaveReg();
6604 return Reg;
6605}
6606
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006607Variable *TargetARM32::makeReg(Type Type, RegNumT RegNum) {
Jan Voungb3401d22015-05-18 09:38:21 -07006608 // There aren't any 64-bit integer registers for ARM32.
6609 assert(Type != IceType_i64);
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006610 assert(AllowTemporaryWithNoReg || RegNum.hasValue());
Jan Voungb3401d22015-05-18 09:38:21 -07006611 Variable *Reg = Func->makeVariable(Type);
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006612 if (RegNum.hasValue())
Jan Voungb3401d22015-05-18 09:38:21 -07006613 Reg->setRegNum(RegNum);
Reed Kotler5fa0a5f2016-02-15 20:01:24 -08006614 else
6615 Reg->setMustHaveReg();
Jan Voungb3401d22015-05-18 09:38:21 -07006616 return Reg;
6617}
6618
John Porto614140e2015-11-23 11:43:13 -08006619void TargetARM32::alignRegisterPow2(Variable *Reg, uint32_t Align,
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006620 RegNumT TmpRegNum) {
Jan Voung55500db2015-05-26 14:25:40 -07006621 assert(llvm::isPowerOf2_32(Align));
Jan Voung0fa6c5a2015-06-01 11:04:04 -07006622 uint32_t RotateAmt;
Jan Voung55500db2015-05-26 14:25:40 -07006623 uint32_t Immed_8;
6624 Operand *Mask;
Andrew Scull57e12682015-09-16 11:30:19 -07006625 // Use AND or BIC to mask off the bits, depending on which immediate fits (if
6626 // it fits at all). Assume Align is usually small, in which case BIC works
6627 // better. Thus, this rounds down to the alignment.
Jan Voung55500db2015-05-26 14:25:40 -07006628 if (OperandARM32FlexImm::canHoldImm(Align - 1, &RotateAmt, &Immed_8)) {
John Porto614140e2015-11-23 11:43:13 -08006629 Mask = legalize(Ctx->getConstantInt32(Align - 1), Legal_Reg | Legal_Flex,
6630 TmpRegNum);
Jan Voung55500db2015-05-26 14:25:40 -07006631 _bic(Reg, Reg, Mask);
6632 } else {
John Porto614140e2015-11-23 11:43:13 -08006633 Mask = legalize(Ctx->getConstantInt32(-Align), Legal_Reg | Legal_Flex,
6634 TmpRegNum);
Jan Voung55500db2015-05-26 14:25:40 -07006635 _and(Reg, Reg, Mask);
6636 }
6637}
6638
Jan Voungb36ad9b2015-04-21 17:01:49 -07006639void TargetARM32::postLower() {
Jim Stichnoth386b52e2016-08-05 15:18:41 -07006640 if (Func->getOptLevel() == Opt_m1)
Jan Voungb36ad9b2015-04-21 17:01:49 -07006641 return;
Jim Stichnoth230d4102015-09-25 17:40:32 -07006642 markRedefinitions();
John Porto562233c2015-10-28 05:47:58 -07006643 Context.availabilityUpdate();
Jan Voungb36ad9b2015-04-21 17:01:49 -07006644}
6645
6646void TargetARM32::makeRandomRegisterPermutation(
Jim Stichnoth8aa39662016-02-10 11:20:30 -08006647 llvm::SmallVectorImpl<RegNumT> &Permutation,
John Portoe82b5602016-02-24 15:58:55 -08006648 const SmallBitVector &ExcludeRegisters, uint64_t Salt) const {
Jan Voungb36ad9b2015-04-21 17:01:49 -07006649 (void)Permutation;
6650 (void)ExcludeRegisters;
Qining Luaee5fa82015-08-20 14:59:03 -07006651 (void)Salt;
Karl Schimpfd4699942016-04-02 09:55:31 -07006652 UnimplementedError(getFlags());
Jan Voungb36ad9b2015-04-21 17:01:49 -07006653}
6654
Jan Voung76bb0be2015-05-14 09:26:19 -07006655void TargetARM32::emit(const ConstantInteger32 *C) const {
Jim Stichnoth20b71f52015-06-24 15:52:24 -07006656 if (!BuildDefs::dump())
Jan Voung76bb0be2015-05-14 09:26:19 -07006657 return;
6658 Ostream &Str = Ctx->getStrEmit();
Jim Stichnoth8ff4b282016-01-04 15:39:06 -08006659 Str << "#" << C->getValue();
Jan Voungb36ad9b2015-04-21 17:01:49 -07006660}
6661
Jan Voung76bb0be2015-05-14 09:26:19 -07006662void TargetARM32::emit(const ConstantInteger64 *) const {
6663 llvm::report_fatal_error("Not expecting to emit 64-bit integers");
Jan Voungb36ad9b2015-04-21 17:01:49 -07006664}
Jan Voung76bb0be2015-05-14 09:26:19 -07006665
6666void TargetARM32::emit(const ConstantFloat *C) const {
Jan Voungb3401d22015-05-18 09:38:21 -07006667 (void)C;
Karl Schimpfd4699942016-04-02 09:55:31 -07006668 UnimplementedError(getFlags());
Jan Voung76bb0be2015-05-14 09:26:19 -07006669}
6670
6671void TargetARM32::emit(const ConstantDouble *C) const {
Jan Voungb3401d22015-05-18 09:38:21 -07006672 (void)C;
Karl Schimpfd4699942016-04-02 09:55:31 -07006673 UnimplementedError(getFlags());
Jan Voung76bb0be2015-05-14 09:26:19 -07006674}
6675
6676void TargetARM32::emit(const ConstantUndef *) const {
6677 llvm::report_fatal_error("undef value encountered by emitter.");
6678}
Jan Voungb36ad9b2015-04-21 17:01:49 -07006679
Jim Stichnoth8ff4b282016-01-04 15:39:06 -08006680void TargetARM32::emit(const ConstantRelocatable *C) const {
6681 if (!BuildDefs::dump())
6682 return;
6683 Ostream &Str = Ctx->getStrEmit();
6684 Str << "#";
6685 emitWithoutPrefix(C);
6686}
6687
John Porto7b3d9cb2015-11-11 14:26:57 -08006688void TargetARM32::lowerInt1ForSelect(Variable *Dest, Operand *Boolean,
6689 Operand *TrueValue, Operand *FalseValue) {
6690 Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
John Porto4a5e6d02015-11-04 09:32:55 -08006691
John Porto7b3d9cb2015-11-11 14:26:57 -08006692 assert(Boolean->getType() == IceType_i1);
6693
6694 bool NeedsAnd1 = false;
6695 if (TrueValue->getType() == IceType_i1) {
6696 assert(FalseValue->getType() == IceType_i1);
6697
6698 Variable *TrueValueV = Func->makeVariable(IceType_i1);
6699 SafeBoolChain Src0Safe = lowerInt1(TrueValueV, TrueValue);
6700 TrueValue = TrueValueV;
6701
6702 Variable *FalseValueV = Func->makeVariable(IceType_i1);
6703 SafeBoolChain Src1Safe = lowerInt1(FalseValueV, FalseValue);
6704 FalseValue = FalseValueV;
6705
6706 NeedsAnd1 = Src0Safe == SBC_No || Src1Safe == SBC_No;
6707 }
6708
6709 Variable *DestLo = (Dest->getType() == IceType_i64)
6710 ? llvm::cast<Variable>(loOperand(Dest))
6711 : Dest;
6712 Variable *DestHi = (Dest->getType() == IceType_i64)
6713 ? llvm::cast<Variable>(hiOperand(Dest))
6714 : nullptr;
6715 Operand *FalseValueLo = (FalseValue->getType() == IceType_i64)
6716 ? loOperand(FalseValue)
6717 : FalseValue;
6718 Operand *FalseValueHi =
6719 (FalseValue->getType() == IceType_i64) ? hiOperand(FalseValue) : nullptr;
6720
6721 Operand *TrueValueLo =
6722 (TrueValue->getType() == IceType_i64) ? loOperand(TrueValue) : TrueValue;
6723 Operand *TrueValueHi =
6724 (TrueValue->getType() == IceType_i64) ? hiOperand(TrueValue) : nullptr;
6725
6726 Variable *T_Lo = makeReg(DestLo->getType());
6727 Variable *T_Hi = (DestHi == nullptr) ? nullptr : makeReg(DestHi->getType());
6728
6729 _mov(T_Lo, legalize(FalseValueLo, Legal_Reg | Legal_Flex));
6730 if (DestHi) {
6731 _mov(T_Hi, legalize(FalseValueHi, Legal_Reg | Legal_Flex));
6732 }
6733
6734 CondWhenTrue Cond(CondARM32::kNone);
6735 // FlagsWereSet is used to determine wether Boolean was folded or not. If not,
6736 // add an explicit _tst instruction below.
6737 bool FlagsWereSet = false;
John Portoeb13acc2015-12-09 05:10:58 -08006738 if (const Inst *Producer = Computations.getProducerOf(Boolean)) {
John Porto7b3d9cb2015-11-11 14:26:57 -08006739 switch (Producer->getKind()) {
6740 default:
John Portoc39ec102015-12-01 13:00:43 -08006741 llvm::report_fatal_error("Unexpected producer.");
John Porto7b3d9cb2015-11-11 14:26:57 -08006742 case Inst::Icmp: {
6743 Cond = lowerIcmpCond(llvm::cast<InstIcmp>(Producer));
6744 FlagsWereSet = true;
6745 } break;
6746 case Inst::Fcmp: {
6747 Cond = lowerFcmpCond(llvm::cast<InstFcmp>(Producer));
6748 FlagsWereSet = true;
6749 } break;
6750 case Inst::Cast: {
6751 const auto *CastProducer = llvm::cast<InstCast>(Producer);
John Porto4a5e6d02015-11-04 09:32:55 -08006752 assert(CastProducer->getCastKind() == InstCast::Trunc);
John Porto7b3d9cb2015-11-11 14:26:57 -08006753 Boolean = CastProducer->getSrc(0);
6754 // No flags were set, so a _tst(Src, 1) will be emitted below. Don't
6755 // bother legalizing Src to a Reg because it will be legalized before
6756 // emitting the tst instruction.
6757 FlagsWereSet = false;
6758 } break;
6759 case Inst::Arithmetic: {
6760 // This is a special case: we eagerly assumed Producer could be folded,
6761 // but in reality, it can't. No reason to panic: we just lower it using
6762 // the regular lowerArithmetic helper.
6763 const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
6764 lowerArithmetic(ArithProducer);
6765 Boolean = ArithProducer->getDest();
6766 // No flags were set, so a _tst(Dest, 1) will be emitted below. Don't
6767 // bother legalizing Dest to a Reg because it will be legalized before
6768 // emitting the tst instruction.
6769 FlagsWereSet = false;
6770 } break;
John Porto4a5e6d02015-11-04 09:32:55 -08006771 }
6772 }
John Porto7b3d9cb2015-11-11 14:26:57 -08006773
6774 if (!FlagsWereSet) {
6775 // No flags have been set, so emit a tst Boolean, 1.
6776 Variable *Src = legalizeToReg(Boolean);
6777 _tst(Src, _1);
6778 Cond = CondWhenTrue(CondARM32::NE); // i.e., CondARM32::NotZero.
6779 }
6780
6781 if (Cond.WhenTrue0 == CondARM32::kNone) {
6782 assert(Cond.WhenTrue1 == CondARM32::kNone);
6783 } else {
6784 _mov_redefined(T_Lo, legalize(TrueValueLo, Legal_Reg | Legal_Flex),
6785 Cond.WhenTrue0);
6786 if (DestHi) {
6787 _mov_redefined(T_Hi, legalize(TrueValueHi, Legal_Reg | Legal_Flex),
6788 Cond.WhenTrue0);
6789 }
6790 }
6791
6792 if (Cond.WhenTrue1 != CondARM32::kNone) {
6793 _mov_redefined(T_Lo, legalize(TrueValueLo, Legal_Reg | Legal_Flex),
6794 Cond.WhenTrue1);
6795 if (DestHi) {
6796 _mov_redefined(T_Hi, legalize(TrueValueHi, Legal_Reg | Legal_Flex),
6797 Cond.WhenTrue1);
6798 }
6799 }
6800
6801 if (NeedsAnd1) {
6802 // We lowered something that is unsafe (i.e., can't provably be zero or
6803 // one). Truncate the result.
6804 _and(T_Lo, T_Lo, _1);
6805 }
6806
6807 _mov(DestLo, T_Lo);
6808 if (DestHi) {
6809 _mov(DestHi, T_Hi);
6810 }
6811}
6812
6813TargetARM32::SafeBoolChain TargetARM32::lowerInt1(Variable *Dest,
6814 Operand *Boolean) {
6815 assert(Boolean->getType() == IceType_i1);
6816 Variable *T = makeReg(IceType_i1);
6817 Operand *_0 =
6818 legalize(Ctx->getConstantZero(IceType_i1), Legal_Reg | Legal_Flex);
6819 Operand *_1 = legalize(Ctx->getConstantInt1(1), Legal_Reg | Legal_Flex);
6820
6821 SafeBoolChain Safe = SBC_Yes;
John Portoeb13acc2015-12-09 05:10:58 -08006822 if (const Inst *Producer = Computations.getProducerOf(Boolean)) {
John Porto7b3d9cb2015-11-11 14:26:57 -08006823 switch (Producer->getKind()) {
6824 default:
John Portoc39ec102015-12-01 13:00:43 -08006825 llvm::report_fatal_error("Unexpected producer.");
John Porto7b3d9cb2015-11-11 14:26:57 -08006826 case Inst::Icmp: {
6827 _mov(T, _0);
6828 CondWhenTrue Cond = lowerIcmpCond(llvm::cast<InstIcmp>(Producer));
6829 assert(Cond.WhenTrue0 != CondARM32::AL);
6830 assert(Cond.WhenTrue0 != CondARM32::kNone);
6831 assert(Cond.WhenTrue1 == CondARM32::kNone);
6832 _mov_redefined(T, _1, Cond.WhenTrue0);
6833 } break;
6834 case Inst::Fcmp: {
6835 _mov(T, _0);
6836 Inst *MovZero = Context.getLastInserted();
6837 CondWhenTrue Cond = lowerFcmpCond(llvm::cast<InstFcmp>(Producer));
6838 if (Cond.WhenTrue0 == CondARM32::AL) {
6839 assert(Cond.WhenTrue1 == CondARM32::kNone);
6840 MovZero->setDeleted();
6841 _mov(T, _1);
6842 } else if (Cond.WhenTrue0 != CondARM32::kNone) {
6843 _mov_redefined(T, _1, Cond.WhenTrue0);
6844 }
6845 if (Cond.WhenTrue1 != CondARM32::kNone) {
6846 assert(Cond.WhenTrue0 != CondARM32::kNone);
6847 assert(Cond.WhenTrue0 != CondARM32::AL);
6848 _mov_redefined(T, _1, Cond.WhenTrue1);
6849 }
6850 } break;
6851 case Inst::Cast: {
6852 const auto *CastProducer = llvm::cast<InstCast>(Producer);
6853 assert(CastProducer->getCastKind() == InstCast::Trunc);
6854 Operand *Src = CastProducer->getSrc(0);
6855 if (Src->getType() == IceType_i64)
6856 Src = loOperand(Src);
6857 _mov(T, legalize(Src, Legal_Reg | Legal_Flex));
6858 Safe = SBC_No;
6859 } break;
6860 case Inst::Arithmetic: {
6861 const auto *ArithProducer = llvm::cast<InstArithmetic>(Producer);
6862 Safe = lowerInt1Arithmetic(ArithProducer);
6863 _mov(T, ArithProducer->getDest());
6864 } break;
6865 }
6866 } else {
6867 _mov(T, legalize(Boolean, Legal_Reg | Legal_Flex));
6868 }
6869
6870 _mov(Dest, T);
6871 return Safe;
John Porto4a5e6d02015-11-04 09:32:55 -08006872}
6873
6874namespace {
6875namespace BoolFolding {
6876bool shouldTrackProducer(const Inst &Instr) {
John Porto7b3d9cb2015-11-11 14:26:57 -08006877 switch (Instr.getKind()) {
6878 default:
6879 return false;
John Porto4a5e6d02015-11-04 09:32:55 -08006880 case Inst::Icmp:
John Porto4a5e6d02015-11-04 09:32:55 -08006881 case Inst::Fcmp:
6882 return true;
John Porto7b3d9cb2015-11-11 14:26:57 -08006883 case Inst::Cast: {
6884 switch (llvm::cast<InstCast>(&Instr)->getCastKind()) {
6885 default:
6886 return false;
John Porto4a5e6d02015-11-04 09:32:55 -08006887 case InstCast::Trunc:
6888 return true;
6889 }
6890 }
John Porto7b3d9cb2015-11-11 14:26:57 -08006891 case Inst::Arithmetic: {
6892 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6893 default:
6894 return false;
6895 case InstArithmetic::And:
6896 case InstArithmetic::Or:
6897 return true;
6898 }
6899 }
6900 }
John Porto4a5e6d02015-11-04 09:32:55 -08006901}
6902
6903bool isValidConsumer(const Inst &Instr) {
John Porto7b3d9cb2015-11-11 14:26:57 -08006904 switch (Instr.getKind()) {
6905 default:
6906 return false;
John Porto4a5e6d02015-11-04 09:32:55 -08006907 case Inst::Br:
6908 return true;
6909 case Inst::Select:
6910 return !isVectorType(Instr.getDest()->getType());
John Porto7b3d9cb2015-11-11 14:26:57 -08006911 case Inst::Cast: {
6912 switch (llvm::cast<InstCast>(&Instr)->getCastKind()) {
6913 default:
6914 return false;
John Porto4a5e6d02015-11-04 09:32:55 -08006915 case InstCast::Sext:
6916 return !isVectorType(Instr.getDest()->getType());
6917 case InstCast::Zext:
6918 return !isVectorType(Instr.getDest()->getType());
6919 }
6920 }
John Porto7b3d9cb2015-11-11 14:26:57 -08006921 case Inst::Arithmetic: {
6922 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6923 default:
6924 return false;
6925 case InstArithmetic::And:
6926 return !isVectorType(Instr.getDest()->getType());
6927 case InstArithmetic::Or:
6928 return !isVectorType(Instr.getDest()->getType());
6929 }
6930 }
6931 }
John Porto4a5e6d02015-11-04 09:32:55 -08006932}
6933} // end of namespace BoolFolding
John Portoeb13acc2015-12-09 05:10:58 -08006934
6935namespace FpFolding {
6936bool shouldTrackProducer(const Inst &Instr) {
6937 switch (Instr.getKind()) {
6938 default:
6939 return false;
6940 case Inst::Arithmetic: {
6941 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6942 default:
6943 return false;
6944 case InstArithmetic::Fmul:
6945 return true;
6946 }
6947 }
6948 }
6949}
6950
6951bool isValidConsumer(const Inst &Instr) {
6952 switch (Instr.getKind()) {
6953 default:
6954 return false;
6955 case Inst::Arithmetic: {
6956 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6957 default:
6958 return false;
6959 case InstArithmetic::Fadd:
6960 case InstArithmetic::Fsub:
6961 return true;
6962 }
6963 }
6964 }
6965}
6966} // end of namespace FpFolding
6967
6968namespace IntFolding {
6969bool shouldTrackProducer(const Inst &Instr) {
6970 switch (Instr.getKind()) {
6971 default:
6972 return false;
6973 case Inst::Arithmetic: {
6974 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6975 default:
6976 return false;
6977 case InstArithmetic::Mul:
6978 return true;
6979 }
6980 }
6981 }
6982}
6983
6984bool isValidConsumer(const Inst &Instr) {
6985 switch (Instr.getKind()) {
6986 default:
6987 return false;
6988 case Inst::Arithmetic: {
6989 switch (llvm::cast<InstArithmetic>(&Instr)->getOp()) {
6990 default:
6991 return false;
6992 case InstArithmetic::Add:
6993 case InstArithmetic::Sub:
6994 return true;
6995 }
6996 }
6997 }
6998}
6999} // end of namespace FpFolding
John Porto4a5e6d02015-11-04 09:32:55 -08007000} // end of anonymous namespace
7001
John Portoeb13acc2015-12-09 05:10:58 -08007002void TargetARM32::ComputationTracker::recordProducers(CfgNode *Node) {
John Porto4a5e6d02015-11-04 09:32:55 -08007003 for (Inst &Instr : Node->getInsts()) {
7004 // Check whether Instr is a valid producer.
7005 Variable *Dest = Instr.getDest();
7006 if (!Instr.isDeleted() // only consider non-deleted instructions; and
7007 && Dest // only instructions with an actual dest var; and
7008 && Dest->getType() == IceType_i1 // only bool-type dest vars; and
7009 && BoolFolding::shouldTrackProducer(Instr)) { // white-listed instr.
John Portoeb13acc2015-12-09 05:10:58 -08007010 KnownComputations.emplace(Dest->getIndex(),
7011 ComputationEntry(&Instr, IceType_i1));
7012 }
7013 if (!Instr.isDeleted() // only consider non-deleted instructions; and
7014 && Dest // only instructions with an actual dest var; and
7015 && isScalarFloatingType(Dest->getType()) // fp-type only dest vars; and
7016 && FpFolding::shouldTrackProducer(Instr)) { // white-listed instr.
7017 KnownComputations.emplace(Dest->getIndex(),
7018 ComputationEntry(&Instr, Dest->getType()));
7019 }
7020 if (!Instr.isDeleted() // only consider non-deleted instructions; and
7021 && Dest // only instructions with an actual dest var; and
7022 && Dest->getType() == IceType_i32 // i32 only dest vars; and
7023 && IntFolding::shouldTrackProducer(Instr)) { // white-listed instr.
7024 KnownComputations.emplace(Dest->getIndex(),
7025 ComputationEntry(&Instr, IceType_i32));
John Porto4a5e6d02015-11-04 09:32:55 -08007026 }
7027 // Check each src variable against the map.
7028 FOREACH_VAR_IN_INST(Var, Instr) {
7029 SizeT VarNum = Var->getIndex();
7030 auto ComputationIter = KnownComputations.find(VarNum);
7031 if (ComputationIter == KnownComputations.end()) {
7032 continue;
7033 }
7034
John Porto7b3d9cb2015-11-11 14:26:57 -08007035 ++ComputationIter->second.NumUses;
John Portoeb13acc2015-12-09 05:10:58 -08007036 switch (ComputationIter->second.ComputationType) {
7037 default:
John Porto4a5e6d02015-11-04 09:32:55 -08007038 KnownComputations.erase(VarNum);
7039 continue;
John Portoeb13acc2015-12-09 05:10:58 -08007040 case IceType_i1:
7041 if (!BoolFolding::isValidConsumer(Instr)) {
7042 KnownComputations.erase(VarNum);
7043 continue;
7044 }
7045 break;
7046 case IceType_i32:
7047 if (IndexOfVarInInst(Var) != 1 || !IntFolding::isValidConsumer(Instr)) {
7048 KnownComputations.erase(VarNum);
7049 continue;
7050 }
7051 break;
7052 case IceType_f32:
7053 case IceType_f64:
7054 if (IndexOfVarInInst(Var) != 1 || !FpFolding::isValidConsumer(Instr)) {
7055 KnownComputations.erase(VarNum);
7056 continue;
7057 }
7058 break;
John Porto4a5e6d02015-11-04 09:32:55 -08007059 }
7060
7061 if (Instr.isLastUse(Var)) {
7062 ComputationIter->second.IsLiveOut = false;
7063 }
7064 }
7065 }
7066
7067 for (auto Iter = KnownComputations.begin(), End = KnownComputations.end();
7068 Iter != End;) {
7069 // Disable the folding if its dest may be live beyond this block.
John Porto7b3d9cb2015-11-11 14:26:57 -08007070 if (Iter->second.IsLiveOut || Iter->second.NumUses > 1) {
John Porto4a5e6d02015-11-04 09:32:55 -08007071 Iter = KnownComputations.erase(Iter);
7072 continue;
7073 }
7074
7075 // Mark as "dead" rather than outright deleting. This is so that other
7076 // peephole style optimizations during or before lowering have access to
7077 // this instruction in undeleted form. See for example
7078 // tryOptimizedCmpxchgCmpBr().
7079 Iter->second.Instr->setDead();
7080 ++Iter;
7081 }
7082}
7083
John Porto52b51572015-12-05 14:16:25 -08007084TargetARM32::Sandboxer::Sandboxer(TargetARM32 *Target,
7085 InstBundleLock::Option BundleOption)
John Portoa1cdd572016-03-01 15:19:29 -08007086 : Target(Target), BundleOption(BundleOption) {}
John Porto52b51572015-12-05 14:16:25 -08007087
John Porto3bf335f2016-01-15 11:17:55 -08007088TargetARM32::Sandboxer::~Sandboxer() {}
John Porto52b51572015-12-05 14:16:25 -08007089
7090namespace {
7091OperandARM32FlexImm *indirectBranchBicMask(Cfg *Func) {
7092 constexpr uint32_t Imm8 = 0xFC; // 0xC000000F
7093 constexpr uint32_t RotateAmt = 2;
7094 return OperandARM32FlexImm::create(Func, IceType_i32, Imm8, RotateAmt);
7095}
7096
7097OperandARM32FlexImm *memOpBicMask(Cfg *Func) {
7098 constexpr uint32_t Imm8 = 0x0C; // 0xC0000000
7099 constexpr uint32_t RotateAmt = 2;
7100 return OperandARM32FlexImm::create(Func, IceType_i32, Imm8, RotateAmt);
7101}
7102
7103static bool baseNeedsBic(Variable *Base) {
7104 return Base->getRegNum() != RegARM32::Reg_r9 &&
7105 Base->getRegNum() != RegARM32::Reg_sp;
7106}
7107} // end of anonymous namespace
7108
John Portoa1cdd572016-03-01 15:19:29 -08007109void TargetARM32::Sandboxer::createAutoBundle() {
7110 Bundler = makeUnique<AutoBundle>(Target, BundleOption);
7111}
7112
John Porto52b51572015-12-05 14:16:25 -08007113void TargetARM32::Sandboxer::add_sp(Operand *AddAmount) {
7114 Variable *SP = Target->getPhysicalRegister(RegARM32::Reg_sp);
John Portoa1cdd572016-03-01 15:19:29 -08007115 if (!Target->NeedSandboxing) {
7116 Target->_add(SP, SP, AddAmount);
7117 return;
John Porto52b51572015-12-05 14:16:25 -08007118 }
John Portoa1cdd572016-03-01 15:19:29 -08007119 createAutoBundle();
7120 Target->_add(SP, SP, AddAmount);
7121 Target->_bic(SP, SP, memOpBicMask(Target->Func));
John Porto52b51572015-12-05 14:16:25 -08007122}
7123
7124void TargetARM32::Sandboxer::align_sp(size_t Alignment) {
7125 Variable *SP = Target->getPhysicalRegister(RegARM32::Reg_sp);
John Portoa1cdd572016-03-01 15:19:29 -08007126 if (!Target->NeedSandboxing) {
7127 Target->alignRegisterPow2(SP, Alignment);
7128 return;
John Porto52b51572015-12-05 14:16:25 -08007129 }
John Portoa1cdd572016-03-01 15:19:29 -08007130 createAutoBundle();
7131 Target->alignRegisterPow2(SP, Alignment);
7132 Target->_bic(SP, SP, memOpBicMask(Target->Func));
John Porto52b51572015-12-05 14:16:25 -08007133}
7134
7135InstARM32Call *TargetARM32::Sandboxer::bl(Variable *ReturnReg,
7136 Operand *CallTarget) {
7137 if (Target->NeedSandboxing) {
John Portoa1cdd572016-03-01 15:19:29 -08007138 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007139 if (auto *CallTargetR = llvm::dyn_cast<Variable>(CallTarget)) {
7140 Target->_bic(CallTargetR, CallTargetR,
7141 indirectBranchBicMask(Target->Func));
7142 }
7143 }
John Porto1d937a82015-12-17 06:19:34 -08007144 return Target->Context.insert<InstARM32Call>(ReturnReg, CallTarget);
John Porto52b51572015-12-05 14:16:25 -08007145}
7146
7147void TargetARM32::Sandboxer::ldr(Variable *Dest, OperandARM32Mem *Mem,
7148 CondARM32::Cond Pred) {
7149 Variable *MemBase = Mem->getBase();
7150 if (Target->NeedSandboxing && baseNeedsBic(MemBase)) {
John Portoa1cdd572016-03-01 15:19:29 -08007151 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007152 assert(!Mem->isRegReg());
7153 Target->_bic(MemBase, MemBase, memOpBicMask(Target->Func), Pred);
7154 }
7155 Target->_ldr(Dest, Mem, Pred);
7156}
7157
7158void TargetARM32::Sandboxer::ldrex(Variable *Dest, OperandARM32Mem *Mem,
7159 CondARM32::Cond Pred) {
7160 Variable *MemBase = Mem->getBase();
7161 if (Target->NeedSandboxing && baseNeedsBic(MemBase)) {
John Portoa1cdd572016-03-01 15:19:29 -08007162 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007163 assert(!Mem->isRegReg());
7164 Target->_bic(MemBase, MemBase, memOpBicMask(Target->Func), Pred);
7165 }
7166 Target->_ldrex(Dest, Mem, Pred);
7167}
7168
7169void TargetARM32::Sandboxer::reset_sp(Variable *Src) {
7170 Variable *SP = Target->getPhysicalRegister(RegARM32::Reg_sp);
John Portoa1cdd572016-03-01 15:19:29 -08007171 if (!Target->NeedSandboxing) {
7172 Target->_mov_redefined(SP, Src);
7173 return;
John Porto52b51572015-12-05 14:16:25 -08007174 }
John Portoa1cdd572016-03-01 15:19:29 -08007175 createAutoBundle();
7176 Target->_mov_redefined(SP, Src);
7177 Target->_bic(SP, SP, memOpBicMask(Target->Func));
John Porto52b51572015-12-05 14:16:25 -08007178}
7179
7180void TargetARM32::Sandboxer::ret(Variable *RetAddr, Variable *RetValue) {
7181 if (Target->NeedSandboxing) {
John Portoa1cdd572016-03-01 15:19:29 -08007182 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007183 Target->_bic(RetAddr, RetAddr, indirectBranchBicMask(Target->Func));
7184 }
7185 Target->_ret(RetAddr, RetValue);
7186}
7187
7188void TargetARM32::Sandboxer::str(Variable *Src, OperandARM32Mem *Mem,
7189 CondARM32::Cond Pred) {
7190 Variable *MemBase = Mem->getBase();
7191 if (Target->NeedSandboxing && baseNeedsBic(MemBase)) {
John Portoa1cdd572016-03-01 15:19:29 -08007192 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007193 assert(!Mem->isRegReg());
7194 Target->_bic(MemBase, MemBase, memOpBicMask(Target->Func), Pred);
7195 }
7196 Target->_str(Src, Mem, Pred);
7197}
7198
7199void TargetARM32::Sandboxer::strex(Variable *Dest, Variable *Src,
7200 OperandARM32Mem *Mem, CondARM32::Cond Pred) {
7201 Variable *MemBase = Mem->getBase();
7202 if (Target->NeedSandboxing && baseNeedsBic(MemBase)) {
John Portoa1cdd572016-03-01 15:19:29 -08007203 createAutoBundle();
John Porto52b51572015-12-05 14:16:25 -08007204 assert(!Mem->isRegReg());
7205 Target->_bic(MemBase, MemBase, memOpBicMask(Target->Func), Pred);
7206 }
7207 Target->_strex(Dest, Src, Mem, Pred);
7208}
7209
7210void TargetARM32::Sandboxer::sub_sp(Operand *SubAmount) {
7211 Variable *SP = Target->getPhysicalRegister(RegARM32::Reg_sp);
John Portoa1cdd572016-03-01 15:19:29 -08007212 if (!Target->NeedSandboxing) {
7213 Target->_sub(SP, SP, SubAmount);
7214 return;
John Porto52b51572015-12-05 14:16:25 -08007215 }
John Portoa1cdd572016-03-01 15:19:29 -08007216 createAutoBundle();
7217 Target->_sub(SP, SP, SubAmount);
7218 Target->_bic(SP, SP, memOpBicMask(Target->Func));
John Porto52b51572015-12-05 14:16:25 -08007219}
7220
Jan Voungb36ad9b2015-04-21 17:01:49 -07007221TargetDataARM32::TargetDataARM32(GlobalContext *Ctx)
7222 : TargetDataLowering(Ctx) {}
7223
John Porto8b1a7052015-06-17 13:20:08 -07007224void TargetDataARM32::lowerGlobals(const VariableDeclarationList &Vars,
Jim Stichnoth467ffe52016-03-29 15:01:06 -07007225 const std::string &SectionSuffix) {
Karl Schimpfd4699942016-04-02 09:55:31 -07007226 const bool IsPIC = getFlags().getUseNonsfi();
7227 switch (getFlags().getOutFileType()) {
Jan Voungb36ad9b2015-04-21 17:01:49 -07007228 case FT_Elf: {
7229 ELFObjectWriter *Writer = Ctx->getObjectWriter();
Jim Stichnoth8ff4b282016-01-04 15:39:06 -08007230 Writer->writeDataSection(Vars, llvm::ELF::R_ARM_ABS32, SectionSuffix,
7231 IsPIC);
Jan Voungb36ad9b2015-04-21 17:01:49 -07007232 } break;
7233 case FT_Asm:
7234 case FT_Iasm: {
John Portof5f02f72015-11-09 14:52:40 -08007235 OstreamLocker _(Ctx);
John Porto8b1a7052015-06-17 13:20:08 -07007236 for (const VariableDeclaration *Var : Vars) {
Jim Stichnothdd6dcfa2016-04-18 12:52:09 -07007237 if (getFlags().matchTranslateOnly(Var->getName(), 0)) {
John Porto8b1a7052015-06-17 13:20:08 -07007238 emitGlobal(*Var, SectionSuffix);
Jan Voungb36ad9b2015-04-21 17:01:49 -07007239 }
7240 }
7241 } break;
7242 }
7243}
7244
John Portoa83bfde2015-09-18 08:43:02 -07007245namespace {
7246template <typename T> struct ConstantPoolEmitterTraits;
7247
7248static_assert(sizeof(uint64_t) == 8,
7249 "uint64_t is supposed to be 8 bytes wide.");
7250
7251// TODO(jpp): implement the following when implementing constant randomization:
7252// * template <> struct ConstantPoolEmitterTraits<uint8_t>
7253// * template <> struct ConstantPoolEmitterTraits<uint16_t>
7254// * template <> struct ConstantPoolEmitterTraits<uint32_t>
7255template <> struct ConstantPoolEmitterTraits<float> {
7256 using ConstantType = ConstantFloat;
7257 static constexpr Type IceType = IceType_f32;
7258 // AsmTag and TypeName can't be constexpr because llvm::StringRef is unhappy
7259 // about them being constexpr.
7260 static const char AsmTag[];
7261 static const char TypeName[];
7262 static uint64_t bitcastToUint64(float Value) {
7263 static_assert(sizeof(Value) == sizeof(uint32_t),
7264 "Float should be 4 bytes.");
Jim Stichnothb0051df2016-01-13 11:39:15 -08007265 const uint32_t IntValue = Utils::bitCopy<uint32_t>(Value);
John Portoa83bfde2015-09-18 08:43:02 -07007266 return static_cast<uint64_t>(IntValue);
7267 }
7268};
7269const char ConstantPoolEmitterTraits<float>::AsmTag[] = ".long";
7270const char ConstantPoolEmitterTraits<float>::TypeName[] = "f32";
7271
7272template <> struct ConstantPoolEmitterTraits<double> {
7273 using ConstantType = ConstantDouble;
7274 static constexpr Type IceType = IceType_f64;
7275 static const char AsmTag[];
7276 static const char TypeName[];
7277 static uint64_t bitcastToUint64(double Value) {
7278 static_assert(sizeof(double) == sizeof(uint64_t),
7279 "Double should be 8 bytes.");
Jim Stichnothb0051df2016-01-13 11:39:15 -08007280 return Utils::bitCopy<uint64_t>(Value);
John Portoa83bfde2015-09-18 08:43:02 -07007281 }
7282};
7283const char ConstantPoolEmitterTraits<double>::AsmTag[] = ".quad";
7284const char ConstantPoolEmitterTraits<double>::TypeName[] = "f64";
7285
7286template <typename T>
7287void emitConstant(
Jim Stichnoth98ba0062016-03-07 09:26:22 -08007288 Ostream &Str,
John Portoa83bfde2015-09-18 08:43:02 -07007289 const typename ConstantPoolEmitterTraits<T>::ConstantType *Const) {
7290 using Traits = ConstantPoolEmitterTraits<T>;
Jim Stichnoth467ffe52016-03-29 15:01:06 -07007291 Str << Const->getLabelName();
John Portoa83bfde2015-09-18 08:43:02 -07007292 Str << ":\n\t" << Traits::AsmTag << "\t0x";
7293 T Value = Const->getValue();
7294 Str.write_hex(Traits::bitcastToUint64(Value));
Jim Stichnoth751e27e2015-12-16 12:40:31 -08007295 Str << "\t/* " << Traits::TypeName << " " << Value << " */\n";
John Portoa83bfde2015-09-18 08:43:02 -07007296}
7297
7298template <typename T> void emitConstantPool(GlobalContext *Ctx) {
7299 if (!BuildDefs::dump()) {
7300 return;
7301 }
7302
7303 using Traits = ConstantPoolEmitterTraits<T>;
7304 static constexpr size_t MinimumAlignment = 4;
7305 SizeT Align = std::max(MinimumAlignment, typeAlignInBytes(Traits::IceType));
7306 assert((Align % 4) == 0 && "Constants should be aligned");
7307 Ostream &Str = Ctx->getStrEmit();
7308 ConstantList Pool = Ctx->getConstantPool(Traits::IceType);
7309
7310 Str << "\t.section\t.rodata.cst" << Align << ",\"aM\",%progbits," << Align
7311 << "\n"
7312 << "\t.align\t" << Align << "\n";
7313
Karl Schimpfd4699942016-04-02 09:55:31 -07007314 if (getFlags().getReorderPooledConstants()) {
John Portoa83bfde2015-09-18 08:43:02 -07007315 // TODO(jpp): add constant pooling.
Karl Schimpfd4699942016-04-02 09:55:31 -07007316 UnimplementedError(getFlags());
John Portoa83bfde2015-09-18 08:43:02 -07007317 }
7318
7319 for (Constant *C : Pool) {
7320 if (!C->getShouldBePooled()) {
7321 continue;
7322 }
7323
Jim Stichnoth98ba0062016-03-07 09:26:22 -08007324 emitConstant<T>(Str, llvm::dyn_cast<typename Traits::ConstantType>(C));
John Portoa83bfde2015-09-18 08:43:02 -07007325 }
7326}
7327} // end of anonymous namespace
7328
John Porto0f86d032015-06-15 07:44:27 -07007329void TargetDataARM32::lowerConstants() {
Karl Schimpfd4699942016-04-02 09:55:31 -07007330 if (getFlags().getDisableTranslation())
Jan Voungb36ad9b2015-04-21 17:01:49 -07007331 return;
Karl Schimpfd4699942016-04-02 09:55:31 -07007332 switch (getFlags().getOutFileType()) {
John Porto7d595132016-02-01 12:43:13 -08007333 case FT_Elf: {
7334 ELFObjectWriter *Writer = Ctx->getObjectWriter();
7335 Writer->writeConstantPool<ConstantFloat>(IceType_f32);
7336 Writer->writeConstantPool<ConstantDouble>(IceType_f64);
7337 } break;
Karl Schimpfc5abdc12015-10-09 13:29:13 -07007338 case FT_Asm:
7339 case FT_Iasm: {
John Portof5f02f72015-11-09 14:52:40 -08007340 OstreamLocker _(Ctx);
John Portoa83bfde2015-09-18 08:43:02 -07007341 emitConstantPool<float>(Ctx);
7342 emitConstantPool<double>(Ctx);
7343 break;
7344 }
John Portoa83bfde2015-09-18 08:43:02 -07007345 }
Jan Voungb36ad9b2015-04-21 17:01:49 -07007346}
7347
Andrew Scull86df4e92015-07-30 13:54:44 -07007348void TargetDataARM32::lowerJumpTables() {
Karl Schimpfd4699942016-04-02 09:55:31 -07007349 if (getFlags().getDisableTranslation())
Andrew Scull86df4e92015-07-30 13:54:44 -07007350 return;
Karl Schimpfd4699942016-04-02 09:55:31 -07007351 switch (getFlags().getOutFileType()) {
John Portoa83bfde2015-09-18 08:43:02 -07007352 case FT_Elf:
John Porto7d595132016-02-01 12:43:13 -08007353 if (!Ctx->getJumpTables().empty()) {
7354 llvm::report_fatal_error("ARM32 does not support jump tables yet.");
7355 }
John Portoa83bfde2015-09-18 08:43:02 -07007356 break;
7357 case FT_Asm:
7358 // Already emitted from Cfg
7359 break;
7360 case FT_Iasm: {
Karl Schimpfc5abdc12015-10-09 13:29:13 -07007361 // TODO(kschimpf): Fill this in when we get more information.
John Portoa83bfde2015-09-18 08:43:02 -07007362 break;
7363 }
7364 }
Andrew Scull86df4e92015-07-30 13:54:44 -07007365}
7366
Jan Voungfb792842015-06-11 15:27:50 -07007367TargetHeaderARM32::TargetHeaderARM32(GlobalContext *Ctx)
Karl Schimpfd4699942016-04-02 09:55:31 -07007368 : TargetHeaderLowering(Ctx), CPUFeatures(getFlags()) {}
Jan Voungfb792842015-06-11 15:27:50 -07007369
7370void TargetHeaderARM32::lower() {
John Portof5f02f72015-11-09 14:52:40 -08007371 OstreamLocker _(Ctx);
Jan Voungfb792842015-06-11 15:27:50 -07007372 Ostream &Str = Ctx->getStrEmit();
7373 Str << ".syntax unified\n";
Andrew Scull57e12682015-09-16 11:30:19 -07007374 // Emit build attributes in format: .eabi_attribute TAG, VALUE. See Sec. 2 of
7375 // "Addenda to, and Errata in the ABI for the ARM architecture"
7376 // http://infocenter.arm.com
7377 // /help/topic/com.arm.doc.ihi0045d/IHI0045D_ABI_addenda.pdf
Jan Voungfb792842015-06-11 15:27:50 -07007378 //
Andrew Scull57e12682015-09-16 11:30:19 -07007379 // Tag_conformance should be be emitted first in a file-scope sub-subsection
7380 // of the first public subsection of the attributes.
Jan Voungfb792842015-06-11 15:27:50 -07007381 Str << ".eabi_attribute 67, \"2.09\" @ Tag_conformance\n";
Andrew Scull57e12682015-09-16 11:30:19 -07007382 // Chromebooks are at least A15, but do A9 for higher compat. For some
7383 // reason, the LLVM ARM asm parser has the .cpu directive override the mattr
7384 // specified on the commandline. So to test hwdiv, we need to set the .cpu
7385 // directive higher (can't just rely on --mattr=...).
Jan Voung6ec369e2015-06-30 11:03:15 -07007386 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) {
7387 Str << ".cpu cortex-a15\n";
7388 } else {
7389 Str << ".cpu cortex-a9\n";
7390 }
7391 Str << ".eabi_attribute 6, 10 @ Tag_CPU_arch: ARMv7\n"
Jan Voungfb792842015-06-11 15:27:50 -07007392 << ".eabi_attribute 7, 65 @ Tag_CPU_arch_profile: App profile\n";
7393 Str << ".eabi_attribute 8, 1 @ Tag_ARM_ISA_use: Yes\n"
7394 << ".eabi_attribute 9, 2 @ Tag_THUMB_ISA_use: Thumb-2\n";
Jan Voungfb792842015-06-11 15:27:50 -07007395 Str << ".fpu neon\n"
7396 << ".eabi_attribute 17, 1 @ Tag_ABI_PCS_GOT_use: permit directly\n"
7397 << ".eabi_attribute 20, 1 @ Tag_ABI_FP_denormal\n"
7398 << ".eabi_attribute 21, 1 @ Tag_ABI_FP_exceptions\n"
7399 << ".eabi_attribute 23, 3 @ Tag_ABI_FP_number_model: IEEE 754\n"
7400 << ".eabi_attribute 34, 1 @ Tag_CPU_unaligned_access\n"
7401 << ".eabi_attribute 24, 1 @ Tag_ABI_align_needed: 8-byte\n"
7402 << ".eabi_attribute 25, 1 @ Tag_ABI_align_preserved: 8-byte\n"
7403 << ".eabi_attribute 28, 1 @ Tag_ABI_VFP_args\n"
7404 << ".eabi_attribute 36, 1 @ Tag_FP_HP_extension\n"
7405 << ".eabi_attribute 38, 1 @ Tag_ABI_FP_16bit_format\n"
7406 << ".eabi_attribute 42, 1 @ Tag_MPextension_use\n"
7407 << ".eabi_attribute 68, 1 @ Tag_Virtualization_use\n";
Jan Voung6ec369e2015-06-30 11:03:15 -07007408 if (CPUFeatures.hasFeature(TargetARM32Features::HWDivArm)) {
7409 Str << ".eabi_attribute 44, 2 @ Tag_DIV_use\n";
7410 }
Jan Voungfb792842015-06-11 15:27:50 -07007411 // Technically R9 is used for TLS with Sandboxing, and we reserve it.
7412 // However, for compatibility with current NaCl LLVM, don't claim that.
7413 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n";
7414}
7415
John Portoe82b5602016-02-24 15:58:55 -08007416SmallBitVector TargetARM32::TypeToRegisterSet[RegARM32::RCARM32_NUM];
7417SmallBitVector TargetARM32::TypeToRegisterSetUnfiltered[RegARM32::RCARM32_NUM];
7418SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM];
Jim Stichnoth94844f12015-11-04 16:06:16 -08007419
John Porto4a566862016-01-04 09:33:41 -08007420} // end of namespace ARM32
Jan Voungb36ad9b2015-04-21 17:01:49 -07007421} // end of namespace Ice