1 //===- subzero/src/IceInstARM32.cpp - ARM32 instruction implementation ----===//
2 //
3 // The Subzero Code Generator
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 ///
10 /// \file
11 /// \brief Implements the InstARM32 and OperandARM32 classes, primarily the
12 /// constructors and the dump()/emit() methods.
13 ///
14 //===----------------------------------------------------------------------===//
15
16 #include "IceInstARM32.h"
17
18 #include "IceAssemblerARM32.h"
19 #include "IceCfg.h"
20 #include "IceCfgNode.h"
21 #include "IceInst.h"
22 #include "IceOperand.h"
23 #include "IceTargetLoweringARM32.h"
24
25 namespace Ice {
26 namespace ARM32 {
27
28 namespace {
29
30 using Register = RegARM32::AllRegisters;
31
32 // maximum number of registers allowed in vpush/vpop.
33 static constexpr SizeT VpushVpopMaxConsecRegs = 16;
34
35 const struct TypeARM32Attributes_ {
36 const char *WidthString; // b, h, <blank>, or d
37 const char *FpWidthString; // i8, i16, i32, f32, f64
38 const char *SVecWidthString; // s8, s16, s32, f32
39 const char *UVecWidthString; // u8, u16, u32, f32
40 int8_t SExtAddrOffsetBits;
41 int8_t ZExtAddrOffsetBits;
42 } TypeARM32Attributes[] = {
43 #define X(tag, elementty, int_width, fp_width, uvec_width, svec_width, sbits, \
44 ubits, rraddr, shaddr) \
45 { int_width, fp_width, svec_width, uvec_width, sbits, ubits } \
46 ,
47 ICETYPEARM32_TABLE
48 #undef X
49 };
50
51 const struct InstARM32ShiftAttributes_ {
52 const char *EmitString;
53 } InstARM32ShiftAttributes[] = {
54 #define X(tag, emit) \
55 { emit } \
56 ,
57 ICEINSTARM32SHIFT_TABLE
58 #undef X
59 };
60
61 const struct InstARM32CondAttributes_ {
62 CondARM32::Cond Opposite;
63 const char *EmitString;
64 } InstARM32CondAttributes[] = {
65 #define X(tag, encode, opp, emit) \
66 { CondARM32::opp, emit } \
67 ,
68 ICEINSTARM32COND_TABLE
69 #undef X
70 };
71
getVecElmtBitsize(Type Ty)72 size_t getVecElmtBitsize(Type Ty) {
73 return typeWidthInBytes(typeElementType(Ty)) * CHAR_BIT;
74 }
75
getWidthString(Type Ty)76 const char *getWidthString(Type Ty) {
77 return TypeARM32Attributes[Ty].WidthString;
78 }
79
getFpWidthString(Type Ty)80 const char *getFpWidthString(Type Ty) {
81 return TypeARM32Attributes[Ty].FpWidthString;
82 }
83
getSVecWidthString(Type Ty)84 const char *getSVecWidthString(Type Ty) {
85 return TypeARM32Attributes[Ty].SVecWidthString;
86 }
87
getUVecWidthString(Type Ty)88 const char *getUVecWidthString(Type Ty) {
89 return TypeARM32Attributes[Ty].UVecWidthString;
90 }
91
getVWidthString(Type Ty,InstARM32::FPSign SignType)92 const char *getVWidthString(Type Ty, InstARM32::FPSign SignType) {
93 switch (SignType) {
94 case InstARM32::FS_None:
95 return getFpWidthString(Ty);
96 case InstARM32::FS_Signed:
97 return getSVecWidthString(Ty);
98 case InstARM32::FS_Unsigned:
99 return getUVecWidthString(Ty);
100 }
101 llvm_unreachable("Invalid Sign Type.");
102 return getFpWidthString(Ty);
103 }
104
105 } // end of anonymous namespace
106
predString(CondARM32::Cond Pred)107 const char *InstARM32Pred::predString(CondARM32::Cond Pred) {
108 return InstARM32CondAttributes[Pred].EmitString;
109 }
110
dumpOpcodePred(Ostream & Str,const char * Opcode,Type Ty) const111 void InstARM32Pred::dumpOpcodePred(Ostream &Str, const char *Opcode,
112 Type Ty) const {
113 Str << Opcode << getPredicate() << "." << Ty;
114 }
115
getOppositeCondition(CondARM32::Cond Cond)116 CondARM32::Cond InstARM32::getOppositeCondition(CondARM32::Cond Cond) {
117 return InstARM32CondAttributes[Cond].Opposite;
118 }
119
startNextInst(const Cfg * Func) const120 void InstARM32::startNextInst(const Cfg *Func) const {
121 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>())
122 Asm->incEmitTextSize(InstSize);
123 }
124
emitUsingTextFixup(const Cfg * Func) const125 void InstARM32::emitUsingTextFixup(const Cfg *Func) const {
126 if (!BuildDefs::dump())
127 return;
128 GlobalContext *Ctx = Func->getContext();
129 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
130 if (getFlags().getDisableHybridAssembly() &&
131 getFlags().getSkipUnimplemented()) {
132 Asm->trap();
133 Asm->resetNeedsTextFixup();
134 return;
135 }
136 std::string Buffer;
137 llvm::raw_string_ostream StrBuf(Buffer);
138 OstreamLocker L(Ctx);
139 Ostream &OldStr = Ctx->getStrEmit();
140 Ctx->setStrEmit(StrBuf);
141 // Start counting instructions here, so that emit() methods don't
142 // need to call this for the first instruction.
143 Asm->resetEmitTextSize();
144 Asm->incEmitTextSize(InstSize);
145 emit(Func);
146 Ctx->setStrEmit(OldStr);
147 if (getFlags().getDisableHybridAssembly()) {
148 if (getFlags().getSkipUnimplemented()) {
149 Asm->trap();
150 } else {
151 llvm::errs() << "Can't assemble: " << StrBuf.str() << "\n";
152 UnimplementedError(getFlags());
153 }
154 Asm->resetNeedsTextFixup();
155 return;
156 }
157 Asm->emitTextInst(StrBuf.str(), Asm->getEmitTextSize());
158 }
159
emitIAS(const Cfg * Func) const160 void InstARM32::emitIAS(const Cfg *Func) const { emitUsingTextFixup(Func); }
161
emitUnaryopGPR(const char * Opcode,const InstARM32Pred * Instr,const Cfg * Func,bool NeedsWidthSuffix)162 void InstARM32Pred::emitUnaryopGPR(const char *Opcode,
163 const InstARM32Pred *Instr, const Cfg *Func,
164 bool NeedsWidthSuffix) {
165 Ostream &Str = Func->getContext()->getStrEmit();
166 assert(Instr->getSrcSize() == 1);
167 Type SrcTy = Instr->getSrc(0)->getType();
168 Str << "\t" << Opcode;
169 if (NeedsWidthSuffix)
170 Str << getWidthString(SrcTy);
171 Str << Instr->getPredicate() << "\t";
172 Instr->getDest()->emit(Func);
173 Str << ", ";
174 Instr->getSrc(0)->emit(Func);
175 }
176
emitUnaryopFP(const char * Opcode,FPSign Sign,const InstARM32Pred * Instr,const Cfg * Func)177 void InstARM32Pred::emitUnaryopFP(const char *Opcode, FPSign Sign,
178 const InstARM32Pred *Instr, const Cfg *Func) {
179 Ostream &Str = Func->getContext()->getStrEmit();
180 assert(Instr->getSrcSize() == 1);
181 Type SrcTy = Instr->getSrc(0)->getType();
182 Str << "\t" << Opcode << Instr->getPredicate();
183 switch (Sign) {
184 case FS_None:
185 Str << getFpWidthString(SrcTy);
186 break;
187 case FS_Signed:
188 Str << getSVecWidthString(SrcTy);
189 break;
190 case FS_Unsigned:
191 Str << getUVecWidthString(SrcTy);
192 break;
193 }
194 Str << "\t";
195 Instr->getDest()->emit(Func);
196 Str << ", ";
197 Instr->getSrc(0)->emit(Func);
198 }
199
emitTwoAddr(const char * Opcode,const InstARM32Pred * Instr,const Cfg * Func)200 void InstARM32Pred::emitTwoAddr(const char *Opcode, const InstARM32Pred *Instr,
201 const Cfg *Func) {
202 if (!BuildDefs::dump())
203 return;
204 Ostream &Str = Func->getContext()->getStrEmit();
205 assert(Instr->getSrcSize() == 2);
206 Variable *Dest = Instr->getDest();
207 assert(Dest == Instr->getSrc(0));
208 Str << "\t" << Opcode << Instr->getPredicate() << "\t";
209 Dest->emit(Func);
210 Str << ", ";
211 Instr->getSrc(1)->emit(Func);
212 }
213
emitThreeAddr(const char * Opcode,const InstARM32Pred * Instr,const Cfg * Func,bool SetFlags)214 void InstARM32Pred::emitThreeAddr(const char *Opcode,
215 const InstARM32Pred *Instr, const Cfg *Func,
216 bool SetFlags) {
217 if (!BuildDefs::dump())
218 return;
219 Ostream &Str = Func->getContext()->getStrEmit();
220 assert(Instr->getSrcSize() == 2);
221 Str << "\t" << Opcode << (SetFlags ? "s" : "") << Instr->getPredicate()
222 << "\t";
223 Instr->getDest()->emit(Func);
224 Str << ", ";
225 Instr->getSrc(0)->emit(Func);
226 Str << ", ";
227 Instr->getSrc(1)->emit(Func);
228 }
229
emitThreeAddrFP(const char * Opcode,FPSign SignType,const InstARM32 * Instr,const Cfg * Func,Type OpType)230 void InstARM32::emitThreeAddrFP(const char *Opcode, FPSign SignType,
231 const InstARM32 *Instr, const Cfg *Func,
232 Type OpType) {
233 if (!BuildDefs::dump())
234 return;
235 Ostream &Str = Func->getContext()->getStrEmit();
236 assert(Instr->getSrcSize() == 2);
237 Str << "\t" << Opcode << getVWidthString(OpType, SignType) << "\t";
238 Instr->getDest()->emit(Func);
239 Str << ", ";
240 Instr->getSrc(0)->emit(Func);
241 Str << ", ";
242 Instr->getSrc(1)->emit(Func);
243 }
244
emitFourAddrFP(const char * Opcode,FPSign SignType,const InstARM32 * Instr,const Cfg * Func)245 void InstARM32::emitFourAddrFP(const char *Opcode, FPSign SignType,
246 const InstARM32 *Instr, const Cfg *Func) {
247 if (!BuildDefs::dump())
248 return;
249 Ostream &Str = Func->getContext()->getStrEmit();
250 assert(Instr->getSrcSize() == 3);
251 assert(Instr->getSrc(0) == Instr->getDest());
252 Str << "\t" << Opcode
253 << getVWidthString(Instr->getDest()->getType(), SignType) << "\t";
254 Instr->getDest()->emit(Func);
255 Str << ", ";
256 Instr->getSrc(1)->emit(Func);
257 Str << ", ";
258 Instr->getSrc(2)->emit(Func);
259 }
260
emitFourAddr(const char * Opcode,const InstARM32Pred * Instr,const Cfg * Func)261 void InstARM32Pred::emitFourAddr(const char *Opcode, const InstARM32Pred *Instr,
262 const Cfg *Func) {
263 if (!BuildDefs::dump())
264 return;
265 Ostream &Str = Func->getContext()->getStrEmit();
266 assert(Instr->getSrcSize() == 3);
267 Str << "\t" << Opcode << Instr->getPredicate() << "\t";
268 Instr->getDest()->emit(Func);
269 Str << ", ";
270 Instr->getSrc(0)->emit(Func);
271 Str << ", ";
272 Instr->getSrc(1)->emit(Func);
273 Str << ", ";
274 Instr->getSrc(2)->emit(Func);
275 }
276
277 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const278 void InstARM32FourAddrGPR<K>::emitIAS(const Cfg *Func) const {
279 emitUsingTextFixup(Func);
280 }
281
282 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const283 void InstARM32FourAddrFP<K>::emitIAS(const Cfg *Func) const {
284 emitUsingTextFixup(Func);
285 }
286
287 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const288 void InstARM32ThreeAddrFP<K>::emitIAS(const Cfg *Func) const {
289 emitUsingTextFixup(Func);
290 }
291
292 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const293 void InstARM32ThreeAddrSignAwareFP<K>::emitIAS(const Cfg *Func) const {
294 InstARM32::emitUsingTextFixup(Func);
295 }
296
emitIAS(const Cfg * Func) const297 template <> void InstARM32Mla::emitIAS(const Cfg *Func) const {
298 assert(getSrcSize() == 3);
299 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
300 Asm->mla(getDest(), getSrc(0), getSrc(1), getSrc(2), getPredicate());
301 if (Asm->needsTextFixup())
302 emitUsingTextFixup(Func);
303 }
304
emitIAS(const Cfg * Func) const305 template <> void InstARM32Mls::emitIAS(const Cfg *Func) const {
306 assert(getSrcSize() == 3);
307 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
308 Asm->mls(getDest(), getSrc(0), getSrc(1), getSrc(2), getPredicate());
309 if (Asm->needsTextFixup())
310 emitUsingTextFixup(Func);
311 }
312
emitCmpLike(const char * Opcode,const InstARM32Pred * Instr,const Cfg * Func)313 void InstARM32Pred::emitCmpLike(const char *Opcode, const InstARM32Pred *Instr,
314 const Cfg *Func) {
315 if (!BuildDefs::dump())
316 return;
317 Ostream &Str = Func->getContext()->getStrEmit();
318 assert(Instr->getSrcSize() == 2);
319 Str << "\t" << Opcode << Instr->getPredicate() << "\t";
320 Instr->getSrc(0)->emit(Func);
321 Str << ", ";
322 Instr->getSrc(1)->emit(Func);
323 }
324
OperandARM32Mem(Cfg *,Type Ty,Variable * Base,ConstantInteger32 * ImmOffset,AddrMode Mode)325 OperandARM32Mem::OperandARM32Mem(Cfg * /* Func */, Type Ty, Variable *Base,
326 ConstantInteger32 *ImmOffset, AddrMode Mode)
327 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(ImmOffset), Index(nullptr),
328 ShiftOp(kNoShift), ShiftAmt(0), Mode(Mode) {
329 // The Neg modes are only needed for Reg +/- Reg.
330 assert(!isNegAddrMode());
331 NumVars = 1;
332 Vars = &this->Base;
333 }
334
OperandARM32Mem(Cfg * Func,Type Ty,Variable * Base,Variable * Index,ShiftKind ShiftOp,uint16_t ShiftAmt,AddrMode Mode)335 OperandARM32Mem::OperandARM32Mem(Cfg *Func, Type Ty, Variable *Base,
336 Variable *Index, ShiftKind ShiftOp,
337 uint16_t ShiftAmt, AddrMode Mode)
338 : OperandARM32(kMem, Ty), Base(Base), ImmOffset(0), Index(Index),
339 ShiftOp(ShiftOp), ShiftAmt(ShiftAmt), Mode(Mode) {
340 if (Index->isRematerializable()) {
341 llvm::report_fatal_error("Rematerializable Index Register is not allowed.");
342 }
343 NumVars = 2;
344 Vars = Func->allocateArrayOf<Variable *>(2);
345 Vars[0] = Base;
346 Vars[1] = Index;
347 }
348
OperandARM32ShAmtImm(ConstantInteger32 * SA)349 OperandARM32ShAmtImm::OperandARM32ShAmtImm(ConstantInteger32 *SA)
350 : OperandARM32(kShAmtImm, IceType_i8), ShAmt(SA) {}
351
canHoldOffset(Type Ty,bool SignExt,int32_t Offset)352 bool OperandARM32Mem::canHoldOffset(Type Ty, bool SignExt, int32_t Offset) {
353 int32_t Bits = SignExt ? TypeARM32Attributes[Ty].SExtAddrOffsetBits
354 : TypeARM32Attributes[Ty].ZExtAddrOffsetBits;
355 if (Bits == 0)
356 return Offset == 0;
357 // Note that encodings for offsets are sign-magnitude for ARM, so we check
358 // with IsAbsoluteUint().
359 // Scalar fp, and vector types require an offset that is aligned to a multiple
360 // of 4.
361 if (isScalarFloatingType(Ty) || isVectorType(Ty))
362 return Utils::IsAligned(Offset, 4) && Utils::IsAbsoluteUint(Bits, Offset);
363 return Utils::IsAbsoluteUint(Bits, Offset);
364 }
365
OperandARM32FlexImm(Cfg *,Type Ty,uint32_t Imm,uint32_t RotateAmt)366 OperandARM32FlexImm::OperandARM32FlexImm(Cfg * /* Func */, Type Ty,
367 uint32_t Imm, uint32_t RotateAmt)
368 : OperandARM32Flex(kFlexImm, Ty), Imm(Imm), RotateAmt(RotateAmt) {
369 NumVars = 0;
370 Vars = nullptr;
371 }
372
canHoldImm(uint32_t Immediate,uint32_t * RotateAmt,uint32_t * Immed_8)373 bool OperandARM32FlexImm::canHoldImm(uint32_t Immediate, uint32_t *RotateAmt,
374 uint32_t *Immed_8) {
375 // Avoid the more expensive test for frequent small immediate values.
376 if (Immediate <= 0xFF) {
377 *RotateAmt = 0;
378 *Immed_8 = Immediate;
379 return true;
380 }
381 // Note that immediate must be unsigned for the test to work correctly.
382 for (int Rot = 1; Rot < 16; Rot++) {
383 uint32_t Imm8 = Utils::rotateLeft32(Immediate, 2 * Rot);
384 if (Imm8 <= 0xFF) {
385 *RotateAmt = Rot;
386 *Immed_8 = Imm8;
387 return true;
388 }
389 }
390 return false;
391 }
392
OperandARM32FlexFpImm(Cfg *,Type Ty,uint32_t ModifiedImm)393 OperandARM32FlexFpImm::OperandARM32FlexFpImm(Cfg * /*Func*/, Type Ty,
394 uint32_t ModifiedImm)
395 : OperandARM32Flex(kFlexFpImm, Ty), ModifiedImm(ModifiedImm) {}
396
canHoldImm(const Operand * C,uint32_t * ModifiedImm)397 bool OperandARM32FlexFpImm::canHoldImm(const Operand *C,
398 uint32_t *ModifiedImm) {
399 switch (C->getType()) {
400 default:
401 llvm::report_fatal_error("Unhandled fp constant type.");
402 case IceType_f32: {
403 // We violate llvm naming conventions a bit here so that the constants are
404 // named after the bit fields they represent. See "A7.5.1 Operation of
405 // modified immediate constants, Floating-point" in the ARM ARM.
406 static constexpr uint32_t a = 0x80000000u;
407 static constexpr uint32_t B = 0x40000000;
408 static constexpr uint32_t bbbbb = 0x3E000000;
409 static constexpr uint32_t cdefgh = 0x01F80000;
410 static constexpr uint32_t AllowedBits = a | B | bbbbb | cdefgh;
411 static_assert(AllowedBits == 0xFFF80000u,
412 "Invalid mask for f32 modified immediates.");
413 const float F32 = llvm::cast<const ConstantFloat>(C)->getValue();
414 const uint32_t I32 = Utils::bitCopy<uint32_t>(F32);
415 if (I32 & ~AllowedBits) {
416 // constant has disallowed bits.
417 return false;
418 }
419
420 if ((I32 & bbbbb) != bbbbb && (I32 & bbbbb)) {
421 // not all bbbbb bits are 0 or 1.
422 return false;
423 }
424
425 if (((I32 & B) != 0) == ((I32 & bbbbb) != 0)) {
426 // B ^ b = 0;
427 return false;
428 }
429
430 *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) | ((I32 & bbbbb) ? 0x40 : 0x00) |
431 ((I32 & cdefgh) >> 19);
432 return true;
433 }
434 case IceType_f64: {
435 static constexpr uint32_t a = 0x80000000u;
436 static constexpr uint32_t B = 0x40000000;
437 static constexpr uint32_t bbbbbbbb = 0x3FC00000;
438 static constexpr uint32_t cdefgh = 0x003F0000;
439 static constexpr uint32_t AllowedBits = a | B | bbbbbbbb | cdefgh;
440 static_assert(AllowedBits == 0xFFFF0000u,
441 "Invalid mask for f64 modified immediates.");
442 const double F64 = llvm::cast<const ConstantDouble>(C)->getValue();
443 const uint64_t I64 = Utils::bitCopy<uint64_t>(F64);
444 if (I64 & 0xFFFFFFFFu) {
445 // constant has disallowed bits.
446 return false;
447 }
448 const uint32_t I32 = I64 >> 32;
449
450 if (I32 & ~AllowedBits) {
451 // constant has disallowed bits.
452 return false;
453 }
454
455 if ((I32 & bbbbbbbb) != bbbbbbbb && (I32 & bbbbbbbb)) {
456 // not all bbbbb bits are 0 or 1.
457 return false;
458 }
459
460 if (((I32 & B) != 0) == ((I32 & bbbbbbbb) != 0)) {
461 // B ^ b = 0;
462 return false;
463 }
464
465 *ModifiedImm = ((I32 & a) ? 0x80 : 0x00) |
466 ((I32 & bbbbbbbb) ? 0x40 : 0x00) | ((I32 & cdefgh) >> 16);
467 return true;
468 }
469 }
470 }
471
OperandARM32FlexFpZero(Cfg *,Type Ty)472 OperandARM32FlexFpZero::OperandARM32FlexFpZero(Cfg * /*Func*/, Type Ty)
473 : OperandARM32Flex(kFlexFpZero, Ty) {}
474
OperandARM32FlexReg(Cfg * Func,Type Ty,Variable * Reg,ShiftKind ShiftOp,Operand * ShiftAmt)475 OperandARM32FlexReg::OperandARM32FlexReg(Cfg *Func, Type Ty, Variable *Reg,
476 ShiftKind ShiftOp, Operand *ShiftAmt)
477 : OperandARM32Flex(kFlexReg, Ty), Reg(Reg), ShiftOp(ShiftOp),
478 ShiftAmt(ShiftAmt) {
479 NumVars = 1;
480 auto *ShiftVar = llvm::dyn_cast_or_null<Variable>(ShiftAmt);
481 if (ShiftVar)
482 ++NumVars;
483 Vars = Func->allocateArrayOf<Variable *>(NumVars);
484 Vars[0] = Reg;
485 if (ShiftVar)
486 Vars[1] = ShiftVar;
487 }
488
InstARM32Br(Cfg * Func,const CfgNode * TargetTrue,const CfgNode * TargetFalse,const InstARM32Label * Label,CondARM32::Cond Pred)489 InstARM32Br::InstARM32Br(Cfg *Func, const CfgNode *TargetTrue,
490 const CfgNode *TargetFalse,
491 const InstARM32Label *Label, CondARM32::Cond Pred)
492 : InstARM32Pred(Func, InstARM32::Br, 0, nullptr, Pred),
493 TargetTrue(TargetTrue), TargetFalse(TargetFalse), Label(Label) {}
494
optimizeBranch(const CfgNode * NextNode)495 bool InstARM32Br::optimizeBranch(const CfgNode *NextNode) {
496 // If there is no next block, then there can be no fallthrough to optimize.
497 if (NextNode == nullptr)
498 return false;
499 // Intra-block conditional branches can't be optimized.
500 if (Label)
501 return false;
502 // If there is no fallthrough node, such as a non-default case label for a
503 // switch instruction, then there is no opportunity to optimize.
504 if (getTargetFalse() == nullptr)
505 return false;
506
507 // Unconditional branch to the next node can be removed.
508 if (isUnconditionalBranch() && getTargetFalse() == NextNode) {
509 assert(getTargetTrue() == nullptr);
510 setDeleted();
511 return true;
512 }
513 // If the fallthrough is to the next node, set fallthrough to nullptr to
514 // indicate.
515 if (getTargetFalse() == NextNode) {
516 TargetFalse = nullptr;
517 return true;
518 }
519 // If TargetTrue is the next node, and TargetFalse is not nullptr (which was
520 // already tested above), then invert the branch condition, swap the targets,
521 // and set new fallthrough to nullptr.
522 if (getTargetTrue() == NextNode) {
523 assert(Predicate != CondARM32::AL);
524 setPredicate(getOppositeCondition(getPredicate()));
525 TargetTrue = getTargetFalse();
526 TargetFalse = nullptr;
527 return true;
528 }
529 return false;
530 }
531
repointEdges(CfgNode * OldNode,CfgNode * NewNode)532 bool InstARM32Br::repointEdges(CfgNode *OldNode, CfgNode *NewNode) {
533 bool Found = false;
534 if (TargetFalse == OldNode) {
535 TargetFalse = NewNode;
536 Found = true;
537 }
538 if (TargetTrue == OldNode) {
539 TargetTrue = NewNode;
540 Found = true;
541 }
542 return Found;
543 }
544
545 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const546 void InstARM32ThreeAddrGPR<K>::emitIAS(const Cfg *Func) const {
547 emitUsingTextFixup(Func);
548 }
549
emitIAS(const Cfg * Func) const550 template <> void InstARM32Adc::emitIAS(const Cfg *Func) const {
551 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
552 Asm->adc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
553 if (Asm->needsTextFixup())
554 emitUsingTextFixup(Func);
555 }
556
emitIAS(const Cfg * Func) const557 template <> void InstARM32Add::emitIAS(const Cfg *Func) const {
558 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
559 Asm->add(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
560 assert(!Asm->needsTextFixup());
561 }
562
emitIAS(const Cfg * Func) const563 template <> void InstARM32And::emitIAS(const Cfg *Func) const {
564 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
565 Asm->and_(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
566 if (Asm->needsTextFixup())
567 emitUsingTextFixup(Func);
568 }
569
emitIAS(const Cfg * Func) const570 template <> void InstARM32Bic::emitIAS(const Cfg *Func) const {
571 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
572 Asm->bic(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
573 if (Asm->needsTextFixup())
574 emitUsingTextFixup(Func);
575 }
576
emitIAS(const Cfg * Func) const577 template <> void InstARM32Eor::emitIAS(const Cfg *Func) const {
578 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
579 Asm->eor(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
580 if (Asm->needsTextFixup())
581 emitUsingTextFixup(Func);
582 }
583
emitIAS(const Cfg * Func) const584 template <> void InstARM32Asr::emitIAS(const Cfg *Func) const {
585 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
586 Asm->asr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
587 if (Asm->needsTextFixup())
588 emitUsingTextFixup(Func);
589 }
590
emitIAS(const Cfg * Func) const591 template <> void InstARM32Lsl::emitIAS(const Cfg *Func) const {
592 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
593 Asm->lsl(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
594 if (Asm->needsTextFixup())
595 emitUsingTextFixup(Func);
596 }
597
emitIAS(const Cfg * Func) const598 template <> void InstARM32Lsr::emitIAS(const Cfg *Func) const {
599 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
600 Asm->lsr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
601 if (Asm->needsTextFixup())
602 emitUsingTextFixup(Func);
603 }
604
emitIAS(const Cfg * Func) const605 template <> void InstARM32Orr::emitIAS(const Cfg *Func) const {
606 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
607 Asm->orr(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
608 if (Asm->needsTextFixup())
609 emitUsingTextFixup(Func);
610 }
611
emitIAS(const Cfg * Func) const612 template <> void InstARM32Mul::emitIAS(const Cfg *Func) const {
613 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
614 Asm->mul(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
615 if (Asm->needsTextFixup())
616 emitUsingTextFixup(Func);
617 }
618
emitIAS(const Cfg * Func) const619 template <> void InstARM32Rsb::emitIAS(const Cfg *Func) const {
620 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
621 Asm->rsb(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
622 if (Asm->needsTextFixup())
623 emitUsingTextFixup(Func);
624 }
625
emitIAS(const Cfg * Func) const626 template <> void InstARM32Rsc::emitIAS(const Cfg *Func) const {
627 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
628 Asm->rsc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
629 if (Asm->needsTextFixup())
630 emitUsingTextFixup(Func);
631 }
632
emitIAS(const Cfg * Func) const633 template <> void InstARM32Sbc::emitIAS(const Cfg *Func) const {
634 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
635 Asm->sbc(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
636 if (Asm->needsTextFixup())
637 emitUsingTextFixup(Func);
638 }
639
emitIAS(const Cfg * Func) const640 template <> void InstARM32Sdiv::emitIAS(const Cfg *Func) const {
641 assert(!SetFlags);
642 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
643 Asm->sdiv(getDest(), getSrc(0), getSrc(1), getPredicate());
644 if (Asm->needsTextFixup())
645 emitUsingTextFixup(Func);
646 }
647
emitIAS(const Cfg * Func) const648 template <> void InstARM32Sub::emitIAS(const Cfg *Func) const {
649 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
650 Asm->sub(getDest(), getSrc(0), getSrc(1), SetFlags, getPredicate());
651 if (Asm->needsTextFixup())
652 emitUsingTextFixup(Func);
653 }
654
emitIAS(const Cfg * Func) const655 template <> void InstARM32Udiv::emitIAS(const Cfg *Func) const {
656 assert(!SetFlags);
657 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
658 Asm->udiv(getDest(), getSrc(0), getSrc(1), getPredicate());
659 if (Asm->needsTextFixup())
660 emitUsingTextFixup(Func);
661 }
662
emitIAS(const Cfg * Func) const663 template <> void InstARM32Vadd::emitIAS(const Cfg *Func) const {
664 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
665 const Variable *Dest = getDest();
666 Type DestTy = Dest->getType();
667 switch (DestTy) {
668 default:
669 llvm::report_fatal_error("Vadd not defined on type " +
670 typeStdString(DestTy));
671 case IceType_v16i8:
672 case IceType_v8i16:
673 case IceType_v4i32:
674 Asm->vaddqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
675 break;
676 case IceType_v4f32:
677 Asm->vaddqf(Dest, getSrc(0), getSrc(1));
678 break;
679 case IceType_f32:
680 Asm->vadds(Dest, getSrc(0), getSrc(1), CondARM32::AL);
681 break;
682 case IceType_f64:
683 Asm->vaddd(Dest, getSrc(0), getSrc(1), CondARM32::AL);
684 break;
685 }
686 assert(!Asm->needsTextFixup());
687 }
688
emitIAS(const Cfg * Func) const689 template <> void InstARM32Vand::emitIAS(const Cfg *Func) const {
690 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
691 const Variable *Dest = getDest();
692 switch (Dest->getType()) {
693 default:
694 llvm::report_fatal_error("Vand not defined on type " +
695 typeStdString(Dest->getType()));
696 case IceType_v4i1:
697 case IceType_v8i1:
698 case IceType_v16i1:
699 case IceType_v16i8:
700 case IceType_v8i16:
701 case IceType_v4i32:
702 Asm->vandq(Dest, getSrc(0), getSrc(1));
703 }
704 assert(!Asm->needsTextFixup());
705 }
706
emitIAS(const Cfg * Func) const707 template <> void InstARM32Vceq::emitIAS(const Cfg *Func) const {
708 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
709 const Variable *Dest = getDest();
710 const Type SrcTy = getSrc(0)->getType();
711 switch (SrcTy) {
712 default:
713 llvm::report_fatal_error("Vceq not defined on type " +
714 typeStdString(SrcTy));
715 case IceType_v4i1:
716 case IceType_v8i1:
717 case IceType_v16i1:
718 case IceType_v16i8:
719 case IceType_v8i16:
720 case IceType_v4i32:
721 Asm->vceqqi(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1));
722 break;
723 case IceType_v4f32:
724 Asm->vceqqs(Dest, getSrc(0), getSrc(1));
725 break;
726 }
727 assert(!Asm->needsTextFixup());
728 }
729
emitIAS(const Cfg * Func) const730 template <> void InstARM32Vcge::emitIAS(const Cfg *Func) const {
731 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
732 const Variable *Dest = getDest();
733 const Type SrcTy = getSrc(0)->getType();
734 switch (SrcTy) {
735 default:
736 llvm::report_fatal_error("Vcge not defined on type " +
737 typeStdString(Dest->getType()));
738 case IceType_v4i1:
739 case IceType_v8i1:
740 case IceType_v16i1:
741 case IceType_v16i8:
742 case IceType_v8i16:
743 case IceType_v4i32: {
744 const Type ElmtTy = typeElementType(SrcTy);
745 assert(Sign != InstARM32::FS_None);
746 switch (Sign) {
747 case InstARM32::FS_None: // defaults to unsigned.
748 llvm_unreachable("Sign should not be FS_None.");
749 case InstARM32::FS_Unsigned:
750 Asm->vcugeqi(ElmtTy, Dest, getSrc(0), getSrc(1));
751 break;
752 case InstARM32::FS_Signed:
753 Asm->vcgeqi(ElmtTy, Dest, getSrc(0), getSrc(1));
754 break;
755 }
756 } break;
757 case IceType_v4f32:
758 Asm->vcgeqs(Dest, getSrc(0), getSrc(1));
759 break;
760 }
761 }
762
emitIAS(const Cfg * Func) const763 template <> void InstARM32Vcgt::emitIAS(const Cfg *Func) const {
764 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
765 const Variable *Dest = getDest();
766 const Type SrcTy = getSrc(0)->getType();
767 switch (SrcTy) {
768 default:
769 llvm::report_fatal_error("Vcgt not defined on type " +
770 typeStdString(Dest->getType()));
771 case IceType_v4i1:
772 case IceType_v8i1:
773 case IceType_v16i1:
774 case IceType_v16i8:
775 case IceType_v8i16:
776 case IceType_v4i32: {
777 const Type ElmtTy = typeElementType(SrcTy);
778 assert(Sign != InstARM32::FS_None);
779 switch (Sign) {
780 case InstARM32::FS_None: // defaults to unsigned.
781 llvm_unreachable("Sign should not be FS_None.");
782 case InstARM32::FS_Unsigned:
783 Asm->vcugtqi(ElmtTy, Dest, getSrc(0), getSrc(1));
784 break;
785 case InstARM32::FS_Signed:
786 Asm->vcgtqi(ElmtTy, Dest, getSrc(0), getSrc(1));
787 break;
788 }
789 } break;
790 case IceType_v4f32:
791 Asm->vcgtqs(Dest, getSrc(0), getSrc(1));
792 break;
793 }
794 }
795
emitIAS(const Cfg * Func) const796 template <> void InstARM32Vbsl::emitIAS(const Cfg *Func) const {
797 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
798 const Variable *Dest = getDest();
799 switch (Dest->getType()) {
800 default:
801 llvm::report_fatal_error("Vbsl not defined on type " +
802 typeStdString(Dest->getType()));
803 case IceType_v4i1:
804 case IceType_v8i1:
805 case IceType_v16i1:
806 case IceType_v16i8:
807 case IceType_v8i16:
808 case IceType_v4i32:
809 Asm->vbslq(Dest, getSrc(0), getSrc(1));
810 }
811 assert(!Asm->needsTextFixup());
812 }
813
emitIAS(const Cfg * Func) const814 template <> void InstARM32Vdiv::emitIAS(const Cfg *Func) const {
815 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
816 const Variable *Dest = getDest();
817 switch (Dest->getType()) {
818 default:
819 // TODO(kschimpf) Figure if more cases are needed.
820 Asm->setNeedsTextFixup();
821 break;
822 case IceType_f32:
823 Asm->vdivs(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
824 break;
825 case IceType_f64:
826 Asm->vdivd(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
827 break;
828 }
829 assert(!Asm->needsTextFixup());
830 }
831
emitIAS(const Cfg * Func) const832 template <> void InstARM32Veor::emitIAS(const Cfg *Func) const {
833 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
834 const Variable *Dest = getDest();
835 if (isVectorType(Dest->getType())) {
836 Asm->veorq(Dest, getSrc(0), getSrc(1));
837 assert(!Asm->needsTextFixup());
838 return;
839 }
840 assert(Dest->getType() == IceType_f64);
841 Asm->veord(Dest, getSrc(0), getSrc(1));
842 assert(!Asm->needsTextFixup());
843 }
844
emitIAS(const Cfg * Func) const845 template <> void InstARM32Vmla::emitIAS(const Cfg *Func) const {
846 // Note: Dest == getSrc(0) for four address FP instructions.
847 assert(getSrcSize() == 3);
848 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
849 const Variable *Dest = getDest();
850 switch (Dest->getType()) {
851 default:
852 // TODO(kschimpf) Figure out how vector operations apply.
853 emitUsingTextFixup(Func);
854 return;
855 case IceType_f32:
856 Asm->vmlas(getDest(), getSrc(1), getSrc(2), CondARM32::AL);
857 assert(!Asm->needsTextFixup());
858 return;
859 case IceType_f64:
860 Asm->vmlad(getDest(), getSrc(1), getSrc(2), CondARM32::AL);
861 assert(!Asm->needsTextFixup());
862 return;
863 }
864 }
865
emitIAS(const Cfg * Func) const866 template <> void InstARM32Vmls::emitIAS(const Cfg *Func) const {
867 // Note: Dest == getSrc(0) for four address FP instructions.
868 assert(getSrcSize() == 3);
869 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
870 const Variable *Dest = getDest();
871 switch (Dest->getType()) {
872 default:
873 // TODO(kschimpf) Figure out how vector operations apply.
874 emitUsingTextFixup(Func);
875 return;
876 case IceType_f32:
877 Asm->vmlss(getDest(), getSrc(1), getSrc(2), CondARM32::AL);
878 assert(!Asm->needsTextFixup());
879 return;
880 case IceType_f64:
881 Asm->vmlsd(getDest(), getSrc(1), getSrc(2), CondARM32::AL);
882 assert(!Asm->needsTextFixup());
883 return;
884 }
885 }
886
emitIAS(const Cfg * Func) const887 template <> void InstARM32Vmvn::emitIAS(const Cfg *Func) const {
888 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
889 const Variable *Dest = getDest();
890 switch (Dest->getType()) {
891 default:
892 llvm::report_fatal_error("Vmvn not defined on type " +
893 typeStdString(Dest->getType()));
894 case IceType_v4i1:
895 case IceType_v8i1:
896 case IceType_v16i1:
897 case IceType_v16i8:
898 case IceType_v8i16:
899 case IceType_v4i32:
900 case IceType_v4f32: {
901 Asm->vmvnq(Dest, getSrc(0));
902 } break;
903 }
904 }
905
emitIAS(const Cfg * Func) const906 template <> void InstARM32Vmovl::emitIAS(const Cfg *Func) const {
907 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
908 const Variable *Dest = getDest();
909 switch (Dest->getType()) {
910 default:
911 llvm::report_fatal_error("Vmovlq not defined on type " +
912 typeStdString(Dest->getType()));
913 case IceType_v4i1:
914 case IceType_v8i1:
915 case IceType_v16i1:
916 case IceType_v16i8:
917 case IceType_v8i16:
918 case IceType_v4i32:
919 case IceType_v4f32: {
920 Asm->vmovlq(Dest, getSrc(0), getSrc(1));
921 } break;
922 }
923 }
924
emitIAS(const Cfg * Func) const925 template <> void InstARM32Vmovh::emitIAS(const Cfg *Func) const {
926 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
927 const Variable *Dest = getDest();
928 switch (Dest->getType()) {
929 default:
930 llvm::report_fatal_error("Vmovhq not defined on type " +
931 typeStdString(Dest->getType()));
932 case IceType_v4i1:
933 case IceType_v8i1:
934 case IceType_v16i1:
935 case IceType_v16i8:
936 case IceType_v8i16:
937 case IceType_v4i32:
938 case IceType_v4f32: {
939 Asm->vmovhq(Dest, getSrc(0), getSrc(1));
940 } break;
941 }
942 }
943
emitIAS(const Cfg * Func) const944 template <> void InstARM32Vmovhl::emitIAS(const Cfg *Func) const {
945 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
946 const Variable *Dest = getDest();
947 switch (Dest->getType()) {
948 default:
949 llvm::report_fatal_error("Vmovhlq not defined on type " +
950 typeStdString(Dest->getType()));
951 case IceType_v4i1:
952 case IceType_v8i1:
953 case IceType_v16i1:
954 case IceType_v16i8:
955 case IceType_v8i16:
956 case IceType_v4i32:
957 case IceType_v4f32: {
958 Asm->vmovhlq(Dest, getSrc(0), getSrc(1));
959 } break;
960 }
961 }
962
emitIAS(const Cfg * Func) const963 template <> void InstARM32Vmovlh::emitIAS(const Cfg *Func) const {
964 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
965 const Variable *Dest = getDest();
966 switch (Dest->getType()) {
967 default:
968 llvm::report_fatal_error("Vmovlhq not defined on type " +
969 typeStdString(Dest->getType()));
970 case IceType_v4i1:
971 case IceType_v8i1:
972 case IceType_v16i1:
973 case IceType_v16i8:
974 case IceType_v8i16:
975 case IceType_v4i32:
976 case IceType_v4f32: {
977 Asm->vmovlhq(Dest, getSrc(0), getSrc(1));
978 } break;
979 }
980 }
981
emitIAS(const Cfg * Func) const982 template <> void InstARM32Vneg::emitIAS(const Cfg *Func) const {
983 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
984 const Variable *Dest = getDest();
985 const Type DestTy = Dest->getType();
986 switch (Dest->getType()) {
987 default:
988 llvm::report_fatal_error("Vneg not defined on type " +
989 typeStdString(Dest->getType()));
990 case IceType_v4i1:
991 case IceType_v8i1:
992 case IceType_v16i1:
993 case IceType_v16i8:
994 case IceType_v8i16:
995 case IceType_v4i32:
996 case IceType_v4f32: {
997 const Type ElmtTy = typeElementType(DestTy);
998 Asm->vnegqs(ElmtTy, Dest, getSrc(0));
999 } break;
1000 }
1001 }
1002
emitIAS(const Cfg * Func) const1003 template <> void InstARM32Vorr::emitIAS(const Cfg *Func) const {
1004 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1005 const Variable *Dest = getDest();
1006 switch (Dest->getType()) {
1007 default:
1008 llvm::report_fatal_error("Vorr not defined on type " +
1009 typeStdString(Dest->getType()));
1010 case IceType_v4i1:
1011 case IceType_v8i1:
1012 case IceType_v16i1:
1013 case IceType_v16i8:
1014 case IceType_v8i16:
1015 case IceType_v4i32:
1016 Asm->vorrq(Dest, getSrc(0), getSrc(1));
1017 }
1018 assert(!Asm->needsTextFixup());
1019 }
1020
emitIAS(const Cfg * Func) const1021 template <> void InstARM32Vshl::emitIAS(const Cfg *Func) const {
1022 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1023 const Variable *Dest = getDest();
1024 const Type DestTy = Dest->getType();
1025 switch (DestTy) {
1026 default:
1027 llvm::report_fatal_error("Vshl not defined on type " +
1028 typeStdString(Dest->getType()));
1029 // TODO(jpp): handle i1 vectors in terms of element count instead of element
1030 // type.
1031 case IceType_v4i1:
1032 case IceType_v8i1:
1033 case IceType_v16i1:
1034 case IceType_v16i8:
1035 case IceType_v8i16:
1036 case IceType_v4i32: {
1037 const Type ElmtTy = typeElementType(DestTy);
1038 assert(Sign != InstARM32::FS_None);
1039 switch (Sign) {
1040 case InstARM32::FS_None: // defaults to unsigned.
1041 case InstARM32::FS_Unsigned:
1042 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) {
1043 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6);
1044 } else {
1045 Asm->vshlqu(ElmtTy, Dest, getSrc(0), getSrc(1));
1046 }
1047 break;
1048 case InstARM32::FS_Signed:
1049 if (const auto *Imm6 = llvm::dyn_cast<ConstantInteger32>(getSrc(1))) {
1050 Asm->vshlqc(ElmtTy, Dest, getSrc(0), Imm6);
1051 } else {
1052 Asm->vshlqi(ElmtTy, Dest, getSrc(0), getSrc(1));
1053 }
1054 break;
1055 }
1056 } break;
1057 }
1058 }
1059
emitIAS(const Cfg * Func) const1060 template <> void InstARM32Vshr::emitIAS(const Cfg *Func) const {
1061 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1062 const Variable *Dest = getDest();
1063 const Type DestTy = Dest->getType();
1064 switch (DestTy) {
1065 default:
1066 llvm::report_fatal_error("Vshr not defined on type " +
1067 typeStdString(Dest->getType()));
1068 // TODO(jpp): handle i1 vectors in terms of element count instead of element
1069 // type.
1070 case IceType_v4i1:
1071 case IceType_v8i1:
1072 case IceType_v16i1:
1073 case IceType_v16i8:
1074 case IceType_v8i16:
1075 case IceType_v4i32: {
1076 const Type ElmtTy = typeElementType(DestTy);
1077 const auto *Imm6 = llvm::cast<ConstantInteger32>(getSrc(1));
1078 switch (Sign) {
1079 case InstARM32::FS_Signed:
1080 case InstARM32::FS_Unsigned:
1081 Asm->vshrqc(ElmtTy, Dest, getSrc(0), Imm6, Sign);
1082 break;
1083 default:
1084 assert(false && "Vshr requires signedness specification.");
1085 }
1086 } break;
1087 }
1088 }
1089
emitIAS(const Cfg * Func) const1090 template <> void InstARM32Vsub::emitIAS(const Cfg *Func) const {
1091 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1092 const Variable *Dest = getDest();
1093 Type DestTy = Dest->getType();
1094 switch (DestTy) {
1095 default:
1096 llvm::report_fatal_error("Vsub not defined on type " +
1097 typeStdString(DestTy));
1098 case IceType_v16i8:
1099 case IceType_v8i16:
1100 case IceType_v4i32:
1101 Asm->vsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1102 break;
1103 case IceType_v4f32:
1104 Asm->vsubqf(Dest, getSrc(0), getSrc(1));
1105 break;
1106 case IceType_f32:
1107 Asm->vsubs(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
1108 break;
1109 case IceType_f64:
1110 Asm->vsubd(getDest(), getSrc(0), getSrc(1), CondARM32::AL);
1111 break;
1112 }
1113 assert(!Asm->needsTextFixup());
1114 }
1115
emitIAS(const Cfg * Func) const1116 template <> void InstARM32Vqadd::emitIAS(const Cfg *Func) const {
1117 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1118 const Variable *Dest = getDest();
1119 Type DestTy = Dest->getType();
1120 switch (DestTy) {
1121 default:
1122 llvm::report_fatal_error("Vqadd not defined on type " +
1123 typeStdString(DestTy));
1124 case IceType_v16i8:
1125 case IceType_v8i16:
1126 case IceType_v4i32:
1127 switch (Sign) {
1128 case InstARM32::FS_None: // defaults to unsigned.
1129 case InstARM32::FS_Unsigned:
1130 Asm->vqaddqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1131 break;
1132 case InstARM32::FS_Signed:
1133 Asm->vqaddqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1134 break;
1135 }
1136 break;
1137 }
1138 assert(!Asm->needsTextFixup());
1139 }
1140
emitIAS(const Cfg * Func) const1141 template <> void InstARM32Vqsub::emitIAS(const Cfg *Func) const {
1142 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1143 const Variable *Dest = getDest();
1144 Type DestTy = Dest->getType();
1145 switch (DestTy) {
1146 default:
1147 llvm::report_fatal_error("Vqsub not defined on type " +
1148 typeStdString(DestTy));
1149 case IceType_v16i8:
1150 case IceType_v8i16:
1151 case IceType_v4i32:
1152 switch (Sign) {
1153 case InstARM32::FS_None: // defaults to unsigned.
1154 case InstARM32::FS_Unsigned:
1155 Asm->vqsubqu(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1156 break;
1157 case InstARM32::FS_Signed:
1158 Asm->vqsubqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1159 break;
1160 }
1161 break;
1162 }
1163 assert(!Asm->needsTextFixup());
1164 }
1165
emitIAS(const Cfg * Func) const1166 template <> void InstARM32Vqmovn2::emitIAS(const Cfg *Func) const {
1167 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1168 const Operand *Src0 = getSrc(0);
1169 const Operand *Src1 = getSrc(1);
1170 Type SrcTy = Src0->getType();
1171 Type DestTy = Dest->getType();
1172 bool Unsigned = true;
1173 bool Saturating = true;
1174 switch (SrcTy) {
1175 default:
1176 llvm::report_fatal_error("Vqmovn2 not defined on type " +
1177 typeStdString(SrcTy));
1178 case IceType_v8i16:
1179 case IceType_v4i32:
1180 switch (Sign) {
1181 case InstARM32::FS_None:
1182 Unsigned = true;
1183 Saturating = false;
1184 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
1185 Saturating);
1186 break;
1187 case InstARM32::FS_Unsigned:
1188 Unsigned = true;
1189 Saturating = true;
1190 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
1191 Saturating);
1192 break;
1193 case InstARM32::FS_Signed:
1194 Unsigned = false;
1195 Saturating = true;
1196 Asm->vqmovn2(typeElementType(DestTy), Dest, Src0, Src1, Unsigned,
1197 Saturating);
1198 break;
1199 }
1200 break;
1201 }
1202 assert(!Asm->needsTextFixup());
1203 }
1204
emitIAS(const Cfg * Func) const1205 template <> void InstARM32Vmulh::emitIAS(const Cfg *Func) const {
1206 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1207 const Operand *Src0 = getSrc(0);
1208 Type SrcTy = Src0->getType();
1209 bool Unsigned = true;
1210 switch (SrcTy) {
1211 default:
1212 llvm::report_fatal_error("Vmulh not defined on type " +
1213 typeStdString(SrcTy));
1214 case IceType_v8i16:
1215 switch (Sign) {
1216 case InstARM32::FS_None: // defaults to unsigned.
1217 case InstARM32::FS_Unsigned:
1218 Unsigned = true;
1219 Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned);
1220 break;
1221 case InstARM32::FS_Signed:
1222 Unsigned = false;
1223 Asm->vmulh(typeElementType(SrcTy), Dest, getSrc(0), getSrc(1), Unsigned);
1224 break;
1225 }
1226 break;
1227 }
1228 assert(!Asm->needsTextFixup());
1229 }
1230
emitIAS(const Cfg * Func) const1231 template <> void InstARM32Vmlap::emitIAS(const Cfg *Func) const {
1232 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1233 const Operand *Src0 = getSrc(0);
1234 const Operand *Src1 = getSrc(1);
1235 Type SrcTy = Src0->getType();
1236 switch (SrcTy) {
1237 default:
1238 llvm::report_fatal_error("Vmlap not defined on type " +
1239 typeStdString(SrcTy));
1240 case IceType_v8i16:
1241 Asm->vmlap(typeElementType(SrcTy), Dest, Src0, Src1);
1242 break;
1243 }
1244 assert(!Asm->needsTextFixup());
1245 }
1246
emitIAS(const Cfg * Func) const1247 template <> void InstARM32Vzip::emitIAS(const Cfg *Func) const {
1248 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1249 const Operand *Src0 = getSrc(0);
1250 const Operand *Src1 = getSrc(1);
1251 Type DestTy = Dest->getType();
1252 Asm->vzip(typeElementType(DestTy), Dest, Src0, Src1);
1253 assert(!Asm->needsTextFixup());
1254 }
1255
emitIAS(const Cfg * Func) const1256 template <> void InstARM32Vmul::emitIAS(const Cfg *Func) const {
1257 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1258 const Variable *Dest = getDest();
1259 const Type DestTy = Dest->getType();
1260 switch (DestTy) {
1261 default:
1262 llvm::report_fatal_error("Vmul not defined on type " +
1263 typeStdString(DestTy));
1264
1265 case IceType_v16i8:
1266 case IceType_v8i16:
1267 case IceType_v4i32:
1268 Asm->vmulqi(typeElementType(DestTy), Dest, getSrc(0), getSrc(1));
1269 break;
1270 case IceType_v4f32:
1271 Asm->vmulqf(Dest, getSrc(0), getSrc(1));
1272 break;
1273 case IceType_f32:
1274 Asm->vmuls(Dest, getSrc(0), getSrc(1), CondARM32::AL);
1275 break;
1276 case IceType_f64:
1277 Asm->vmuld(Dest, getSrc(0), getSrc(1), CondARM32::AL);
1278 break;
1279 }
1280 }
1281
InstARM32Call(Cfg * Func,Variable * Dest,Operand * CallTarget)1282 InstARM32Call::InstARM32Call(Cfg *Func, Variable *Dest, Operand *CallTarget)
1283 : InstARM32(Func, InstARM32::Call, 1, Dest) {
1284 HasSideEffects = true;
1285 addSource(CallTarget);
1286 }
1287
InstARM32Label(Cfg * Func,TargetARM32 * Target)1288 InstARM32Label::InstARM32Label(Cfg *Func, TargetARM32 *Target)
1289 : InstARM32(Func, InstARM32::Label, 0, nullptr),
1290 Number(Target->makeNextLabelNumber()) {
1291 if (BuildDefs::dump()) {
1292 Name = GlobalString::createWithString(
1293 Func->getContext(),
1294 ".L" + Func->getFunctionName() + "$local$__" + std::to_string(Number));
1295 } else {
1296 Name = GlobalString::createWithoutString(Func->getContext());
1297 }
1298 }
1299
1300 namespace {
1301 // Requirements for Push/Pop:
1302 // 1) All the Variables have the same type;
1303 // 2) All the variables have registers assigned to them.
validatePushOrPopRegisterListOrDie(const VarList & RegList)1304 void validatePushOrPopRegisterListOrDie(const VarList &RegList) {
1305 Type PreviousTy = IceType_void;
1306 for (Variable *Reg : RegList) {
1307 if (PreviousTy != IceType_void && Reg->getType() != PreviousTy) {
1308 llvm::report_fatal_error("Type mismatch when popping/pushing "
1309 "registers.");
1310 }
1311
1312 if (!Reg->hasReg()) {
1313 llvm::report_fatal_error("Push/pop operand does not have a register "
1314 "assigned to it.");
1315 }
1316
1317 PreviousTy = Reg->getType();
1318 }
1319 }
1320 } // end of anonymous namespace
1321
emit(const Cfg * Func) const1322 void InstARM32RegisterStackOp::emit(const Cfg *Func) const {
1323 if (!BuildDefs::dump())
1324 return;
1325 emitUsingForm(Func, Emit_Text);
1326 }
1327
emitIAS(const Cfg * Func) const1328 void InstARM32RegisterStackOp::emitIAS(const Cfg *Func) const {
1329 emitUsingForm(Func, Emit_Binary);
1330 assert(!Func->getAssembler<ARM32::AssemblerARM32>()->needsTextFixup());
1331 }
1332
dump(const Cfg * Func) const1333 void InstARM32RegisterStackOp::dump(const Cfg *Func) const {
1334 if (!BuildDefs::dump())
1335 return;
1336 Ostream &Str = Func->getContext()->getStrDump();
1337 Str << getDumpOpcode() << " ";
1338 SizeT NumRegs = getNumStackRegs();
1339 for (SizeT I = 0; I < NumRegs; ++I) {
1340 if (I > 0)
1341 Str << ", ";
1342 getStackReg(I)->dump(Func);
1343 }
1344 }
1345
emitGPRsAsText(const Cfg * Func) const1346 void InstARM32RegisterStackOp::emitGPRsAsText(const Cfg *Func) const {
1347 if (!BuildDefs::dump())
1348 return;
1349 Ostream &Str = Func->getContext()->getStrEmit();
1350 Str << "\t" << getGPROpcode() << "\t{";
1351 getStackReg(0)->emit(Func);
1352 const SizeT NumRegs = getNumStackRegs();
1353 for (SizeT i = 1; i < NumRegs; ++i) {
1354 Str << ", ";
1355 getStackReg(i)->emit(Func);
1356 }
1357 Str << "}";
1358 }
1359
emitSRegsAsText(const Cfg * Func,const Variable * BaseReg,SizeT RegCount) const1360 void InstARM32RegisterStackOp::emitSRegsAsText(const Cfg *Func,
1361 const Variable *BaseReg,
1362 SizeT RegCount) const {
1363 if (!BuildDefs::dump())
1364 return;
1365 Ostream &Str = Func->getContext()->getStrEmit();
1366 Str << "\t" << getSRegOpcode() << "\t{";
1367 bool IsFirst = true;
1368 const auto Base = BaseReg->getRegNum();
1369 for (SizeT i = 0; i < RegCount; ++i) {
1370 if (IsFirst)
1371 IsFirst = false;
1372 else
1373 Str << ", ";
1374 Str << RegARM32::getRegName(RegNumT::fixme(Base + i));
1375 }
1376 Str << "}";
1377 }
1378
emitSRegsOp(const Cfg * Func,EmitForm Form,const Variable * BaseReg,SizeT RegCount,SizeT InstIndex) const1379 void InstARM32RegisterStackOp::emitSRegsOp(const Cfg *Func, EmitForm Form,
1380 const Variable *BaseReg,
1381 SizeT RegCount,
1382 SizeT InstIndex) const {
1383 if (Form == Emit_Text && BuildDefs::dump() && InstIndex > 0) {
1384 startNextInst(Func);
1385 Func->getContext()->getStrEmit() << "\n";
1386 }
1387 emitSRegs(Func, Form, BaseReg, RegCount);
1388 }
1389
1390 namespace {
1391
isAssignedConsecutiveRegisters(const Variable * Before,const Variable * After)1392 bool isAssignedConsecutiveRegisters(const Variable *Before,
1393 const Variable *After) {
1394 assert(Before->hasReg());
1395 assert(After->hasReg());
1396 return RegNumT::fixme(Before->getRegNum() + 1) == After->getRegNum();
1397 }
1398
1399 } // end of anonymous namespace
1400
emitUsingForm(const Cfg * Func,const EmitForm Form) const1401 void InstARM32RegisterStackOp::emitUsingForm(const Cfg *Func,
1402 const EmitForm Form) const {
1403 SizeT NumRegs = getNumStackRegs();
1404 assert(NumRegs);
1405
1406 const auto *Reg = llvm::cast<Variable>(getStackReg(0));
1407 if (isScalarIntegerType(Reg->getType())) {
1408 // Push/pop GPR registers.
1409 SizeT IntegerCount = 0;
1410 ARM32::IValueT GPRegisters = 0;
1411 const Variable *LastDest = nullptr;
1412 for (SizeT i = 0; i < NumRegs; ++i) {
1413 const Variable *Var = getStackReg(i);
1414 assert(Var->hasReg() && "stack op only applies to registers");
1415 const RegARM32::GPRRegister Reg =
1416 RegARM32::getEncodedGPR(Var->getRegNum());
1417 LastDest = Var;
1418 GPRegisters |= (1 << Reg);
1419 ++IntegerCount;
1420 }
1421 if (IntegerCount == 1) {
1422 emitSingleGPR(Func, Form, LastDest);
1423 } else {
1424 emitMultipleGPRs(Func, Form, GPRegisters);
1425 }
1426 return;
1427 }
1428
1429 // Push/pop floating point registers. Divide into a list of instructions,
1430 // defined on consecutive register ranges. Then generate the corresponding
1431 // instructions.
1432
1433 // Typical max number of registers ranges pushed/popd is no more than 5.
1434 llvm::SmallVector<std::pair<const Variable *, SizeT>, 5> InstData;
1435 const Variable *BaseReg = nullptr;
1436 SizeT RegCount = 0;
1437 for (SizeT i = 0; i < NumRegs; ++i) {
1438 const Variable *NextReg = getStackReg(i);
1439 assert(NextReg->hasReg());
1440 if (BaseReg == nullptr) {
1441 BaseReg = NextReg;
1442 RegCount = 1;
1443 } else if (RegCount < VpushVpopMaxConsecRegs &&
1444 isAssignedConsecutiveRegisters(Reg, NextReg)) {
1445 ++RegCount;
1446 } else {
1447 InstData.emplace_back(BaseReg, RegCount);
1448 BaseReg = NextReg;
1449 RegCount = 1;
1450 }
1451 Reg = NextReg;
1452 }
1453 if (RegCount) {
1454 InstData.emplace_back(BaseReg, RegCount);
1455 }
1456 SizeT InstCount = 0;
1457 if (llvm::isa<InstARM32Push>(*this)) {
1458 for (const auto &Pair : InstData)
1459 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++);
1460 return;
1461 }
1462 assert(llvm::isa<InstARM32Pop>(*this));
1463 for (const auto &Pair : reverse_range(InstData))
1464 emitSRegsOp(Func, Form, Pair.first, Pair.second, InstCount++);
1465 }
1466
InstARM32Pop(Cfg * Func,const VarList & Dests)1467 InstARM32Pop::InstARM32Pop(Cfg *Func, const VarList &Dests)
1468 : InstARM32RegisterStackOp(Func, InstARM32::Pop, 0, nullptr), Dests(Dests) {
1469 // Track modifications to Dests separately via FakeDefs. Also, a pop
1470 // instruction affects the stack pointer and so it should not be allowed to
1471 // be automatically dead-code eliminated. This is automatic since we leave
1472 // the Dest as nullptr.
1473 validatePushOrPopRegisterListOrDie(Dests);
1474 }
1475
InstARM32Push(Cfg * Func,const VarList & Srcs)1476 InstARM32Push::InstARM32Push(Cfg *Func, const VarList &Srcs)
1477 : InstARM32RegisterStackOp(Func, InstARM32::Push, Srcs.size(), nullptr) {
1478 validatePushOrPopRegisterListOrDie(Srcs);
1479 for (Variable *Source : Srcs) {
1480 addSource(Source);
1481 }
1482 }
1483
InstARM32Ret(Cfg * Func,Variable * LR,Variable * Source)1484 InstARM32Ret::InstARM32Ret(Cfg *Func, Variable *LR, Variable *Source)
1485 : InstARM32(Func, InstARM32::Ret, Source ? 2 : 1, nullptr) {
1486 addSource(LR);
1487 if (Source)
1488 addSource(Source);
1489 }
1490
InstARM32Str(Cfg * Func,Variable * Value,OperandARM32Mem * Mem,CondARM32::Cond Predicate)1491 InstARM32Str::InstARM32Str(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
1492 CondARM32::Cond Predicate)
1493 : InstARM32Pred(Func, InstARM32::Str, 2, nullptr, Predicate) {
1494 addSource(Value);
1495 addSource(Mem);
1496 }
1497
InstARM32Strex(Cfg * Func,Variable * Dest,Variable * Value,OperandARM32Mem * Mem,CondARM32::Cond Predicate)1498 InstARM32Strex::InstARM32Strex(Cfg *Func, Variable *Dest, Variable *Value,
1499 OperandARM32Mem *Mem, CondARM32::Cond Predicate)
1500 : InstARM32Pred(Func, InstARM32::Strex, 2, Dest, Predicate) {
1501 addSource(Value);
1502 addSource(Mem);
1503 }
1504
InstARM32Vstr1(Cfg * Func,Variable * Value,OperandARM32Mem * Mem,CondARM32::Cond Predicate,SizeT Size)1505 InstARM32Vstr1::InstARM32Vstr1(Cfg *Func, Variable *Value, OperandARM32Mem *Mem,
1506 CondARM32::Cond Predicate, SizeT Size)
1507 : InstARM32Pred(Func, InstARM32::Vstr1, 2, nullptr, Predicate) {
1508 addSource(Value);
1509 addSource(Mem);
1510 this->Size = Size;
1511 }
1512
InstARM32Vdup(Cfg * Func,Variable * Dest,Variable * Src,IValueT Idx)1513 InstARM32Vdup::InstARM32Vdup(Cfg *Func, Variable *Dest, Variable *Src,
1514 IValueT Idx)
1515 : InstARM32Pred(Func, InstARM32::Vdup, 1, Dest, CondARM32::AL), Idx(Idx) {
1516 addSource(Src);
1517 }
1518
InstARM32Trap(Cfg * Func)1519 InstARM32Trap::InstARM32Trap(Cfg *Func)
1520 : InstARM32(Func, InstARM32::Trap, 0, nullptr) {}
1521
InstARM32Umull(Cfg * Func,Variable * DestLo,Variable * DestHi,Variable * Src0,Variable * Src1,CondARM32::Cond Predicate)1522 InstARM32Umull::InstARM32Umull(Cfg *Func, Variable *DestLo, Variable *DestHi,
1523 Variable *Src0, Variable *Src1,
1524 CondARM32::Cond Predicate)
1525 : InstARM32Pred(Func, InstARM32::Umull, 2, DestLo, Predicate),
1526 // DestHi is expected to have a FakeDef inserted by the lowering code.
1527 DestHi(DestHi) {
1528 addSource(Src0);
1529 addSource(Src1);
1530 }
1531
InstARM32Vcvt(Cfg * Func,Variable * Dest,Variable * Src,VcvtVariant Variant,CondARM32::Cond Predicate)1532 InstARM32Vcvt::InstARM32Vcvt(Cfg *Func, Variable *Dest, Variable *Src,
1533 VcvtVariant Variant, CondARM32::Cond Predicate)
1534 : InstARM32Pred(Func, InstARM32::Vcvt, 1, Dest, Predicate),
1535 Variant(Variant) {
1536 addSource(Src);
1537 }
1538
InstARM32Mov(Cfg * Func,Variable * Dest,Operand * Src,CondARM32::Cond Predicate)1539 InstARM32Mov::InstARM32Mov(Cfg *Func, Variable *Dest, Operand *Src,
1540 CondARM32::Cond Predicate)
1541 : InstARM32Pred(Func, InstARM32::Mov, 2, Dest, Predicate) {
1542 auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest);
1543 auto *Src64 = llvm::dyn_cast<Variable64On32>(Src);
1544
1545 assert(Dest64 == nullptr || Src64 == nullptr);
1546
1547 if (Dest64 != nullptr) {
1548 // this-> is needed below because there is a parameter named Dest.
1549 this->Dest = Dest64->getLo();
1550 DestHi = Dest64->getHi();
1551 }
1552
1553 if (Src64 == nullptr) {
1554 addSource(Src);
1555 } else {
1556 addSource(Src64->getLo());
1557 addSource(Src64->getHi());
1558 }
1559 }
1560
1561 namespace {
1562
1563 // These next two functions find the D register that maps to the half of the Q
1564 // register that this instruction is accessing.
getDRegister(const Variable * Src,uint32_t Index)1565 Register getDRegister(const Variable *Src, uint32_t Index) {
1566 assert(Src->hasReg());
1567 const auto SrcReg = Src->getRegNum();
1568
1569 const RegARM32::RegTableType &SrcEntry = RegARM32::RegTable[SrcReg];
1570 assert(SrcEntry.IsVec128);
1571
1572 const uint32_t NumElements = typeNumElements(Src->getType());
1573
1574 // This code assumes the Aliases list goes Q_n, S_2n, S_2n+1. The asserts in
1575 // the next two branches help to check that this is still true.
1576 if (Index < NumElements / 2) {
1577 // We have a Q register that's made up of two D registers. This assert is
1578 // to help ensure that we picked the right D register.
1579 //
1580 // TODO(jpp): find a way to do this that doesn't rely on ordering of the
1581 // alias list.
1582 assert(RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding + 1 ==
1583 RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding);
1584 return static_cast<Register>(SrcEntry.Aliases[1]);
1585 } else {
1586 // We have a Q register that's made up of two D registers. This assert is
1587 // to help ensure that we picked the right D register.
1588 //
1589 // TODO(jpp): find a way to do this that doesn't rely on ordering of the
1590 // alias list.
1591 assert(RegARM32::RegTable[SrcEntry.Aliases[2]].Encoding - 1 ==
1592 RegARM32::RegTable[SrcEntry.Aliases[1]].Encoding);
1593 return static_cast<Register>(SrcEntry.Aliases[2]);
1594 }
1595 }
1596
adjustDIndex(Type Ty,uint32_t DIndex)1597 uint32_t adjustDIndex(Type Ty, uint32_t DIndex) {
1598 // If Ty is a vector of i1, we may need to adjust DIndex. This is needed
1599 // because, e.g., the second i1 in a v4i1 is accessed with a
1600 //
1601 // vmov.s8 Qd[4], Rn
1602 switch (Ty) {
1603 case IceType_v4i1:
1604 return DIndex * 4;
1605 case IceType_v8i1:
1606 return DIndex * 2;
1607 case IceType_v16i1:
1608 return DIndex;
1609 default:
1610 return DIndex;
1611 }
1612 }
1613
getDIndex(Type Ty,uint32_t NumElements,uint32_t Index)1614 uint32_t getDIndex(Type Ty, uint32_t NumElements, uint32_t Index) {
1615 const uint32_t DIndex =
1616 (Index < NumElements / 2) ? Index : Index - (NumElements / 2);
1617 return adjustDIndex(Ty, DIndex);
1618 }
1619
1620 // For floating point values, we can insertelement or extractelement by moving
1621 // directly from an S register. This function finds the right one.
getSRegister(const Variable * Src,uint32_t Index)1622 Register getSRegister(const Variable *Src, uint32_t Index) {
1623 assert(Src->hasReg());
1624 const auto SrcReg = Src->getRegNum();
1625
1626 // For floating point values, we need to be allocated to Q0 - Q7, so we can
1627 // directly access the value we want as one of the S registers.
1628 assert(Src->getType() == IceType_v4f32);
1629 assert(SrcReg < RegARM32::Reg_q8);
1630
1631 // This part assumes the register alias list goes q0, d0, d1, s0, s1, s2, s3.
1632 assert(Index < 4);
1633
1634 // TODO(jpp): find a way to do this that doesn't rely on ordering of the alias
1635 // list.
1636 return static_cast<Register>(RegARM32::RegTable[SrcReg].Aliases[Index + 3]);
1637 }
1638
1639 } // end of anonymous namespace
1640
emit(const Cfg * Func) const1641 void InstARM32Extract::emit(const Cfg *Func) const {
1642 Ostream &Str = Func->getContext()->getStrEmit();
1643 const Type DestTy = getDest()->getType();
1644
1645 const auto *Src = llvm::cast<Variable>(getSrc(0));
1646
1647 if (isIntegerType(DestTy)) {
1648 Str << "\t"
1649 << "vmov" << getPredicate();
1650 const uint32_t BitSize = typeWidthInBytes(DestTy) * CHAR_BIT;
1651 if (BitSize < 32) {
1652 Str << ".s" << BitSize;
1653 } else {
1654 Str << "." << BitSize;
1655 }
1656 Str << "\t";
1657 getDest()->emit(Func);
1658 Str << ", ";
1659
1660 const Type SrcTy = Src->getType();
1661 const size_t VectorSize = typeNumElements(SrcTy);
1662
1663 const Register SrcReg = getDRegister(Src, Index);
1664
1665 Str << RegARM32::RegTable[SrcReg].Name;
1666 Str << "[" << getDIndex(SrcTy, VectorSize, Index) << "]";
1667 } else if (isFloatingType(DestTy)) {
1668 const Register SrcReg = getSRegister(Src, Index);
1669
1670 Str << "\t"
1671 << "vmov" << getPredicate() << ".f32"
1672 << "\t";
1673 getDest()->emit(Func);
1674 Str << ", " << RegARM32::RegTable[SrcReg].Name;
1675 } else {
1676 assert(false && "Invalid extract type");
1677 }
1678 }
1679
emitIAS(const Cfg * Func) const1680 void InstARM32Extract::emitIAS(const Cfg *Func) const {
1681 const Operand *Dest = getDest();
1682 const Type DestTy = Dest->getType();
1683 const Operand *Src = getSrc(0);
1684 const Type SrcTy = Src->getType();
1685 assert(isVectorType(Src->getType()));
1686 assert(DestTy == typeElementType(Src->getType()));
1687 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1688 if (isIntegerType(DestTy)) {
1689 Asm->vmovrqi(Dest, Src, adjustDIndex(SrcTy, Index), getPredicate());
1690 assert(!Asm->needsTextFixup());
1691 return;
1692 }
1693 assert(isFloatingType(DestTy));
1694 Asm->vmovsqi(Dest, Src, Index, getPredicate());
1695 assert(!Asm->needsTextFixup());
1696 }
1697
1698 namespace {
insertionType(Type Ty)1699 Type insertionType(Type Ty) {
1700 assert(isVectorType(Ty));
1701 switch (Ty) {
1702 case IceType_v4i1:
1703 return IceType_v4i32;
1704 case IceType_v8i1:
1705 return IceType_v8i16;
1706 case IceType_v16i1:
1707 return IceType_v16i8;
1708 default:
1709 return Ty;
1710 }
1711 }
1712 } // end of anonymous namespace
1713
emit(const Cfg * Func) const1714 void InstARM32Insert::emit(const Cfg *Func) const {
1715 Ostream &Str = Func->getContext()->getStrEmit();
1716 const Variable *Dest = getDest();
1717 const auto *Src = llvm::cast<Variable>(getSrc(0));
1718 const Type DestTy = insertionType(getDest()->getType());
1719 assert(isVectorType(DestTy));
1720
1721 if (isIntegerType(DestTy)) {
1722 Str << "\t"
1723 << "vmov" << getPredicate();
1724 const size_t BitSize = typeWidthInBytes(typeElementType(DestTy)) * CHAR_BIT;
1725 Str << "." << BitSize << "\t";
1726
1727 const size_t VectorSize = typeNumElements(DestTy);
1728 const Register DestReg = getDRegister(Dest, Index);
1729 const uint32_t Index =
1730 getDIndex(insertionType(DestTy), VectorSize, this->Index);
1731 Str << RegARM32::RegTable[DestReg].Name;
1732 Str << "[" << Index << "], ";
1733 Src->emit(Func);
1734 } else if (isFloatingType(DestTy)) {
1735 Str << "\t"
1736 << "vmov" << getPredicate() << ".f32"
1737 << "\t";
1738 const Register DestReg = getSRegister(Dest, Index);
1739 Str << RegARM32::RegTable[DestReg].Name << ", ";
1740 Src->emit(Func);
1741 } else {
1742 assert(false && "Invalid insert type");
1743 }
1744 }
1745
emitIAS(const Cfg * Func) const1746 void InstARM32Insert::emitIAS(const Cfg *Func) const {
1747 const Variable *Dest = getDest();
1748 const auto *Src = llvm::cast<Variable>(getSrc(0));
1749 const Type DestTy = insertionType(Dest->getType());
1750 const Type SrcTy = typeElementType(DestTy);
1751 assert(SrcTy == Src->getType() || Src->getType() == IceType_i1);
1752 assert(isVectorType(DestTy));
1753 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1754 if (isIntegerType(SrcTy)) {
1755 Asm->vmovqir(Dest->asType(Func, DestTy, Dest->getRegNum()),
1756 adjustDIndex(DestTy, Index),
1757 Src->asType(Func, SrcTy, Src->getRegNum()), getPredicate());
1758 assert(!Asm->needsTextFixup());
1759 return;
1760 }
1761 assert(isFloatingType(SrcTy));
1762 Asm->vmovqis(Dest, Index, Src, getPredicate());
1763 assert(!Asm->needsTextFixup());
1764 }
1765
1766 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const1767 void InstARM32CmpLike<K>::emitIAS(const Cfg *Func) const {
1768 emitUsingTextFixup(Func);
1769 }
1770
emitIAS(const Cfg * Func) const1771 template <> void InstARM32Cmn::emitIAS(const Cfg *Func) const {
1772 assert(getSrcSize() == 2);
1773 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1774 Asm->cmn(getSrc(0), getSrc(1), getPredicate());
1775 if (Asm->needsTextFixup())
1776 emitUsingTextFixup(Func);
1777 }
1778
emitIAS(const Cfg * Func) const1779 template <> void InstARM32Cmp::emitIAS(const Cfg *Func) const {
1780 assert(getSrcSize() == 2);
1781 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1782 Asm->cmp(getSrc(0), getSrc(1), getPredicate());
1783 if (Asm->needsTextFixup())
1784 emitUsingTextFixup(Func);
1785 }
1786
emitIAS(const Cfg * Func) const1787 template <> void InstARM32Tst::emitIAS(const Cfg *Func) const {
1788 assert(getSrcSize() == 2);
1789 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1790 Asm->tst(getSrc(0), getSrc(1), getPredicate());
1791 if (Asm->needsTextFixup())
1792 emitUsingTextFixup(Func);
1793 }
1794
InstARM32Dmb(Cfg * Func)1795 InstARM32Dmb::InstARM32Dmb(Cfg *Func)
1796 : InstARM32Pred(Func, InstARM32::Dmb, 0, nullptr, CondARM32::AL) {}
1797
InstARM32Nop(Cfg * Func)1798 InstARM32Nop::InstARM32Nop(Cfg *Func)
1799 : InstARM32Pred(Func, InstARM32::Nop, 0, nullptr, CondARM32::AL) {}
1800
InstARM32Vcmp(Cfg * Func,Variable * Src0,Operand * Src1,CondARM32::Cond Predicate)1801 InstARM32Vcmp::InstARM32Vcmp(Cfg *Func, Variable *Src0, Operand *Src1,
1802 CondARM32::Cond Predicate)
1803 : InstARM32Pred(Func, InstARM32::Vcmp, 2, nullptr, Predicate) {
1804 HasSideEffects = true;
1805 addSource(Src0);
1806 addSource(Src1);
1807 }
1808
InstARM32Vmrs(Cfg * Func,CondARM32::Cond Predicate)1809 InstARM32Vmrs::InstARM32Vmrs(Cfg *Func, CondARM32::Cond Predicate)
1810 : InstARM32Pred(Func, InstARM32::Vmrs, 0, nullptr, Predicate) {
1811 HasSideEffects = true;
1812 }
1813
InstARM32Vabs(Cfg * Func,Variable * Dest,Variable * Src,CondARM32::Cond Predicate)1814 InstARM32Vabs::InstARM32Vabs(Cfg *Func, Variable *Dest, Variable *Src,
1815 CondARM32::Cond Predicate)
1816 : InstARM32Pred(Func, InstARM32::Vabs, 1, Dest, Predicate) {
1817 addSource(Src);
1818 }
1819
1820 // ======================== Dump routines ======================== //
1821
1822 // Two-addr ops
1823 template <> const char *InstARM32Movt::Opcode = "movt";
1824 // Unary ops
1825 template <> const char *InstARM32Movw::Opcode = "movw";
1826 template <> const char *InstARM32Clz::Opcode = "clz";
1827 template <> const char *InstARM32Mvn::Opcode = "mvn";
1828 template <> const char *InstARM32Rbit::Opcode = "rbit";
1829 template <> const char *InstARM32Rev::Opcode = "rev";
1830 template <> const char *InstARM32Sxt::Opcode = "sxt"; // still requires b/h
1831 template <> const char *InstARM32Uxt::Opcode = "uxt"; // still requires b/h
1832 // FP
1833 template <> const char *InstARM32Vsqrt::Opcode = "vsqrt";
1834 // Mov-like ops
1835 template <> const char *InstARM32Ldr::Opcode = "ldr";
1836 template <> const char *InstARM32Ldrex::Opcode = "ldrex";
1837 template <> const char *InstARM32Vldr1d::Opcode = "vldr1d";
1838 template <> const char *InstARM32Vldr1q::Opcode = "vldr1q";
1839 // Three-addr ops
1840 template <> const char *InstARM32Adc::Opcode = "adc";
1841 template <> const char *InstARM32Add::Opcode = "add";
1842 template <> const char *InstARM32And::Opcode = "and";
1843 template <> const char *InstARM32Asr::Opcode = "asr";
1844 template <> const char *InstARM32Bic::Opcode = "bic";
1845 template <> const char *InstARM32Eor::Opcode = "eor";
1846 template <> const char *InstARM32Lsl::Opcode = "lsl";
1847 template <> const char *InstARM32Lsr::Opcode = "lsr";
1848 template <> const char *InstARM32Mul::Opcode = "mul";
1849 template <> const char *InstARM32Orr::Opcode = "orr";
1850 template <> const char *InstARM32Rsb::Opcode = "rsb";
1851 template <> const char *InstARM32Rsc::Opcode = "rsc";
1852 template <> const char *InstARM32Sbc::Opcode = "sbc";
1853 template <> const char *InstARM32Sdiv::Opcode = "sdiv";
1854 template <> const char *InstARM32Sub::Opcode = "sub";
1855 template <> const char *InstARM32Udiv::Opcode = "udiv";
1856 // FP
1857 template <> const char *InstARM32Vadd::Opcode = "vadd";
1858 template <> const char *InstARM32Vand::Opcode = "vand";
1859 template <> const char *InstARM32Vbsl::Opcode = "vbsl";
1860 template <> const char *InstARM32Vceq::Opcode = "vceq";
1861 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcge>::Opcode = "vcge";
1862 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vcgt>::Opcode = "vcgt";
1863 template <> const char *InstARM32Vdiv::Opcode = "vdiv";
1864 template <> const char *InstARM32Veor::Opcode = "veor";
1865 template <> const char *InstARM32Vmla::Opcode = "vmla";
1866 template <> const char *InstARM32Vmls::Opcode = "vmls";
1867 template <> const char *InstARM32Vmul::Opcode = "vmul";
1868 template <> const char *InstARM32Vmvn::Opcode = "vmvn";
1869 template <> const char *InstARM32Vmovl::Opcode = "vmovl";
1870 template <> const char *InstARM32Vmovh::Opcode = "vmovh";
1871 template <> const char *InstARM32Vmovhl::Opcode = "vmovhl";
1872 template <> const char *InstARM32Vmovlh::Opcode = "vmovlh";
1873 template <> const char *InstARM32Vorr::Opcode = "vorr";
1874 template <> const char *InstARM32UnaryopFP<InstARM32::Vneg>::Opcode = "vneg";
1875 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshl>::Opcode = "vshl";
1876 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vshr>::Opcode = "vshr";
1877 template <> const char *InstARM32Vsub::Opcode = "vsub";
1878 template <>
1879 const char *InstARM32ThreeAddrFP<InstARM32::Vqadd>::Opcode = "vqadd";
1880 template <>
1881 const char *InstARM32ThreeAddrFP<InstARM32::Vqsub>::Opcode = "vqsub";
1882 template <>
1883 const char *InstARM32ThreeAddrFP<InstARM32::Vqmovn2>::Opcode = "vqmovn2";
1884 template <>
1885 const char *InstARM32ThreeAddrFP<InstARM32::Vmulh>::Opcode = "vmulh";
1886 template <>
1887 const char *InstARM32ThreeAddrFP<InstARM32::Vmlap>::Opcode = "vmlap";
1888 template <> const char *InstARM32ThreeAddrFP<InstARM32::Vzip>::Opcode = "vzip";
1889 // Four-addr ops
1890 template <> const char *InstARM32Mla::Opcode = "mla";
1891 template <> const char *InstARM32Mls::Opcode = "mls";
1892 // Cmp-like ops
1893 template <> const char *InstARM32Cmn::Opcode = "cmn";
1894 template <> const char *InstARM32Cmp::Opcode = "cmp";
1895 template <> const char *InstARM32Tst::Opcode = "tst";
1896
dump(const Cfg * Func) const1897 void InstARM32::dump(const Cfg *Func) const {
1898 if (!BuildDefs::dump())
1899 return;
1900 Ostream &Str = Func->getContext()->getStrDump();
1901 Str << "[ARM32] ";
1902 Inst::dump(Func);
1903 }
1904
emitMultiDestSingleSource(const Cfg * Func) const1905 void InstARM32Mov::emitMultiDestSingleSource(const Cfg *Func) const {
1906 if (!BuildDefs::dump())
1907 return;
1908 Ostream &Str = Func->getContext()->getStrEmit();
1909 Variable *DestLo = getDest();
1910 Variable *DestHi = getDestHi();
1911 auto *Src = llvm::cast<Variable>(getSrc(0));
1912
1913 assert(DestHi->hasReg());
1914 assert(DestLo->hasReg());
1915 assert(Src->hasReg());
1916
1917 Str << "\t"
1918 "vmov" << getPredicate() << "\t";
1919 DestLo->emit(Func);
1920 Str << ", ";
1921 DestHi->emit(Func);
1922 Str << ", ";
1923 Src->emit(Func);
1924 }
1925
emitSingleDestMultiSource(const Cfg * Func) const1926 void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const {
1927 if (!BuildDefs::dump())
1928 return;
1929 Ostream &Str = Func->getContext()->getStrEmit();
1930 Variable *Dest = getDest();
1931 auto *SrcLo = llvm::cast<Variable>(getSrc(0));
1932 auto *SrcHi = llvm::cast<Variable>(getSrc(1));
1933
1934 assert(SrcHi->hasReg());
1935 assert(SrcLo->hasReg());
1936 assert(Dest->hasReg());
1937 assert(getSrcSize() == 2);
1938
1939 Str << "\t"
1940 "vmov" << getPredicate() << "\t";
1941 Dest->emit(Func);
1942 Str << ", ";
1943 SrcLo->emit(Func);
1944 Str << ", ";
1945 SrcHi->emit(Func);
1946 }
1947
1948 namespace {
1949
isVariableWithoutRegister(const Operand * Op)1950 bool isVariableWithoutRegister(const Operand *Op) {
1951 if (const auto *OpV = llvm::dyn_cast<Variable>(Op)) {
1952 return !OpV->hasReg();
1953 }
1954 return false;
1955 }
isMemoryAccess(Operand * Op)1956 bool isMemoryAccess(Operand *Op) {
1957 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op);
1958 }
1959
isMoveBetweenCoreAndVFPRegisters(Variable * Dest,Operand * Src)1960 bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) {
1961 const Type DestTy = Dest->getType();
1962 const Type SrcTy = Src->getType();
1963 return !isVectorType(DestTy) && !isVectorType(SrcTy) &&
1964 (isScalarIntegerType(DestTy) == isScalarFloatingType(SrcTy));
1965 }
1966
1967 } // end of anonymous namespace
1968
emitSingleDestSingleSource(const Cfg * Func) const1969 void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
1970 if (!BuildDefs::dump())
1971 return;
1972 Ostream &Str = Func->getContext()->getStrEmit();
1973 Variable *Dest = getDest();
1974
1975 if (!Dest->hasReg()) {
1976 llvm::report_fatal_error("mov can't store.");
1977 }
1978
1979 Operand *Src0 = getSrc(0);
1980 if (isMemoryAccess(Src0)) {
1981 llvm::report_fatal_error("mov can't load.");
1982 }
1983
1984 Type Ty = Dest->getType();
1985 const bool IsVector = isVectorType(Ty);
1986 const bool IsScalarFP = isScalarFloatingType(Ty);
1987 const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
1988 const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove);
1989 const char *Opcode = IsVMove ? "vmov" : "mov";
1990 // when vmov{c}'ing, we need to emit a width string. Otherwise, the
1991 // assembler might be tempted to assume we want a vector vmov{c}, and that
1992 // is disallowed because ARM.
1993 const char *WidthString = !CoreVFPMove ? getFpWidthString(Ty) : "";
1994 CondARM32::Cond Cond = getPredicate();
1995 if (IsVector)
1996 assert(CondARM32::isUnconditional(Cond) &&
1997 "Moves on vectors must be unconditional!");
1998 Str << "\t" << Opcode;
1999 if (IsVMove) {
2000 Str << Cond << WidthString;
2001 } else {
2002 Str << WidthString << Cond;
2003 }
2004 Str << "\t";
2005 Dest->emit(Func);
2006 Str << ", ";
2007 Src0->emit(Func);
2008 }
2009
emit(const Cfg * Func) const2010 void InstARM32Mov::emit(const Cfg *Func) const {
2011 if (!BuildDefs::dump())
2012 return;
2013 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
2014 if (isMultiDest()) {
2015 emitMultiDestSingleSource(Func);
2016 return;
2017 }
2018
2019 if (isMultiSource()) {
2020 emitSingleDestMultiSource(Func);
2021 return;
2022 }
2023
2024 emitSingleDestSingleSource(Func);
2025 }
2026
emitIAS(const Cfg * Func) const2027 void InstARM32Mov::emitIAS(const Cfg *Func) const {
2028 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2029 const Variable *Dest = getDest();
2030 Operand *Src0 = getSrc(0);
2031 const CondARM32::Cond Cond = getPredicate();
2032 if (!Dest->hasReg()) {
2033 llvm::report_fatal_error("mov can't store.");
2034 }
2035 if (isMemoryAccess(Src0)) {
2036 llvm::report_fatal_error("mov can't load.");
2037 }
2038
2039 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
2040 if (isMultiDest()) {
2041 Asm->vmovrrd(Dest, getDestHi(), Src0, Cond);
2042 return;
2043 }
2044 if (isMultiSource()) {
2045 Asm->vmovdrr(Dest, Src0, getSrc(1), Cond);
2046 return;
2047 }
2048
2049 const Type DestTy = Dest->getType();
2050 const Type SrcTy = Src0->getType();
2051 switch (DestTy) {
2052 default:
2053 break; // Error
2054 case IceType_i1:
2055 case IceType_i8:
2056 case IceType_i16:
2057 case IceType_i32:
2058 switch (SrcTy) {
2059 default:
2060 break; // Error
2061 case IceType_i1:
2062 case IceType_i8:
2063 case IceType_i16:
2064 case IceType_i32:
2065 case IceType_i64:
2066 Asm->mov(Dest, Src0, Cond);
2067 return;
2068 case IceType_f32:
2069 Asm->vmovrs(Dest, Src0, Cond);
2070 return;
2071 }
2072 break; // Error
2073 case IceType_i64:
2074 if (isScalarIntegerType(SrcTy)) {
2075 Asm->mov(Dest, Src0, Cond);
2076 return;
2077 }
2078 if (SrcTy == IceType_f64) {
2079 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2080 Asm->vmovdd(Dest, Var, Cond);
2081 return;
2082 }
2083 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2084 Asm->vmovd(Dest, FpImm, Cond);
2085 return;
2086 }
2087 }
2088 break; // Error
2089 case IceType_f32:
2090 switch (SrcTy) {
2091 default:
2092 break; // Error
2093 case IceType_i1:
2094 case IceType_i8:
2095 case IceType_i16:
2096 case IceType_i32:
2097 return Asm->vmovsr(Dest, Src0, Cond);
2098 case IceType_f32:
2099 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2100 Asm->vmovss(Dest, Var, Cond);
2101 return;
2102 }
2103 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2104 Asm->vmovs(Dest, FpImm, Cond);
2105 return;
2106 }
2107 break; // Error
2108 }
2109 break; // Error
2110 case IceType_f64:
2111 if (SrcTy == IceType_f64) {
2112 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2113 Asm->vmovdd(Dest, Var, Cond);
2114 return;
2115 }
2116 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2117 Asm->vmovd(Dest, FpImm, Cond);
2118 return;
2119 }
2120 }
2121 break; // Error
2122 // TODO(jpp): Remove vectors of i1.
2123 case IceType_v4i1:
2124 case IceType_v8i1:
2125 case IceType_v16i1:
2126 case IceType_v16i8:
2127 case IceType_v8i16:
2128 case IceType_v4i32:
2129 case IceType_v4f32:
2130 assert(CondARM32::isUnconditional(Cond) &&
2131 "Moves on vector must be unconditional!");
2132 if (isVectorType(SrcTy)) {
2133 // Mov between different Src and Dest types is used for bitcasting
2134 // vectors. We still want to make sure SrcTy is a vector type.
2135 Asm->vorrq(Dest, Src0, Src0);
2136 return;
2137 } else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) {
2138 // Mov with constant argument, allowing the initializing all elements of
2139 // the vector.
2140 if (Asm->vmovqc(Dest, C))
2141 return;
2142 }
2143 }
2144 llvm::report_fatal_error("Mov: don't know how to move " +
2145 typeStdString(SrcTy) + " to " +
2146 typeStdString(DestTy));
2147 }
2148
dump(const Cfg * Func) const2149 void InstARM32Mov::dump(const Cfg *Func) const {
2150 if (!BuildDefs::dump())
2151 return;
2152 assert(getSrcSize() == 1 || getSrcSize() == 2);
2153 Ostream &Str = Func->getContext()->getStrDump();
2154 Variable *Dest = getDest();
2155 Variable *DestHi = getDestHi();
2156 Dest->dump(Func);
2157 if (DestHi) {
2158 Str << ", ";
2159 DestHi->dump(Func);
2160 }
2161
2162 dumpOpcodePred(Str, " = mov", getDest()->getType());
2163 Str << " ";
2164
2165 dumpSources(Func);
2166 }
2167
emit(const Cfg * Func) const2168 void InstARM32Br::emit(const Cfg *Func) const {
2169 if (!BuildDefs::dump())
2170 return;
2171 Ostream &Str = Func->getContext()->getStrEmit();
2172 Str << "\t"
2173 "b" << getPredicate() << "\t";
2174 if (Label) {
2175 Str << Label->getLabelName();
2176 } else {
2177 if (isUnconditionalBranch()) {
2178 Str << getTargetFalse()->getAsmName();
2179 } else {
2180 Str << getTargetTrue()->getAsmName();
2181 if (getTargetFalse()) {
2182 startNextInst(Func);
2183 Str << "\n\t"
2184 << "b"
2185 << "\t" << getTargetFalse()->getAsmName();
2186 }
2187 }
2188 }
2189 }
2190
emitIAS(const Cfg * Func) const2191 void InstARM32Br::emitIAS(const Cfg *Func) const {
2192 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2193 if (Label) {
2194 Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber()), getPredicate());
2195 } else if (isUnconditionalBranch()) {
2196 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()),
2197 getPredicate());
2198 } else {
2199 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex()),
2200 getPredicate());
2201 if (const CfgNode *False = getTargetFalse())
2202 Asm->b(Asm->getOrCreateCfgNodeLabel(False->getIndex()), CondARM32::AL);
2203 }
2204 if (Asm->needsTextFixup())
2205 emitUsingTextFixup(Func);
2206 }
2207
dump(const Cfg * Func) const2208 void InstARM32Br::dump(const Cfg *Func) const {
2209 if (!BuildDefs::dump())
2210 return;
2211 Ostream &Str = Func->getContext()->getStrDump();
2212 Str << "br ";
2213
2214 if (getPredicate() == CondARM32::AL) {
2215 if (Label) {
2216 Str << "label %" << Label->getLabelName();
2217 } else {
2218 Str << "label %" << getTargetFalse()->getName();
2219 }
2220 return;
2221 }
2222
2223 if (Label) {
2224 Str << getPredicate() << ", label %" << Label->getLabelName();
2225 } else {
2226 Str << getPredicate() << ", label %" << getTargetTrue()->getName();
2227 if (getTargetFalse()) {
2228 Str << ", label %" << getTargetFalse()->getName();
2229 }
2230 }
2231 }
2232
emit(const Cfg * Func) const2233 void InstARM32Call::emit(const Cfg *Func) const {
2234 if (!BuildDefs::dump())
2235 return;
2236 Ostream &Str = Func->getContext()->getStrEmit();
2237 assert(getSrcSize() == 1);
2238 if (llvm::isa<ConstantInteger32>(getCallTarget())) {
2239 // This shouldn't happen (typically have to copy the full 32-bits to a
2240 // register and do an indirect jump).
2241 llvm::report_fatal_error("ARM32Call to ConstantInteger32");
2242 } else if (const auto *CallTarget =
2243 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
2244 // Calls only have 24-bits, but the linker should insert veneers to extend
2245 // the range if needed.
2246 Str << "\t"
2247 "bl"
2248 "\t";
2249 CallTarget->emitWithoutPrefix(Func->getTarget());
2250 } else {
2251 Str << "\t"
2252 "blx"
2253 "\t";
2254 getCallTarget()->emit(Func);
2255 }
2256 }
2257
emitIAS(const Cfg * Func) const2258 void InstARM32Call::emitIAS(const Cfg *Func) const {
2259 assert(getSrcSize() == 1);
2260 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2261 if (llvm::isa<ConstantInteger32>(getCallTarget())) {
2262 // This shouldn't happen (typically have to copy the full 32-bits to a
2263 // register and do an indirect jump).
2264 llvm::report_fatal_error("ARM32Call to ConstantInteger32");
2265 } else if (const auto *CallTarget =
2266 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
2267 // Calls only have 24-bits, but the linker should insert veneers to extend
2268 // the range if needed.
2269 Asm->bl(CallTarget);
2270 } else {
2271 Asm->blx(getCallTarget());
2272 }
2273 if (Asm->needsTextFixup())
2274 return emitUsingTextFixup(Func);
2275 }
2276
dump(const Cfg * Func) const2277 void InstARM32Call::dump(const Cfg *Func) const {
2278 if (!BuildDefs::dump())
2279 return;
2280 Ostream &Str = Func->getContext()->getStrDump();
2281 if (getDest()) {
2282 dumpDest(Func);
2283 Str << " = ";
2284 }
2285 Str << "call ";
2286 getCallTarget()->dump(Func);
2287 }
2288
emit(const Cfg * Func) const2289 void InstARM32Label::emit(const Cfg *Func) const {
2290 if (!BuildDefs::dump())
2291 return;
2292 // A label is not really an instruction. Hence, we need to fix the
2293 // emitted text size.
2294 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>())
2295 Asm->decEmitTextSize(InstSize);
2296 Ostream &Str = Func->getContext()->getStrEmit();
2297 Str << getLabelName() << ":";
2298 }
2299
emitIAS(const Cfg * Func) const2300 void InstARM32Label::emitIAS(const Cfg *Func) const {
2301 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2302 Asm->bindLocalLabel(this, Number);
2303 if (OffsetReloc != nullptr) {
2304 Asm->bindRelocOffset(OffsetReloc);
2305 }
2306 if (Asm->needsTextFixup())
2307 emitUsingTextFixup(Func);
2308 }
2309
dump(const Cfg * Func) const2310 void InstARM32Label::dump(const Cfg *Func) const {
2311 if (!BuildDefs::dump())
2312 return;
2313 Ostream &Str = Func->getContext()->getStrDump();
2314 Str << getLabelName() << ":";
2315 }
2316
2317 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2318 void InstARM32LoadBase<K>::emitIAS(const Cfg *Func) const {
2319 emitUsingTextFixup(Func);
2320 }
2321
emit(const Cfg * Func) const2322 template <> void InstARM32Ldr::emit(const Cfg *Func) const {
2323 if (!BuildDefs::dump())
2324 return;
2325 Ostream &Str = Func->getContext()->getStrEmit();
2326 assert(getSrcSize() == 1);
2327 assert(getDest()->hasReg());
2328 Variable *Dest = getDest();
2329 Type Ty = Dest->getType();
2330 const bool IsVector = isVectorType(Ty);
2331 const bool IsScalarFloat = isScalarFloatingType(Ty);
2332 const char *ActualOpcode =
2333 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2334 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2335 Str << "\t" << ActualOpcode;
2336 const bool IsVInst = IsVector || IsScalarFloat;
2337 if (IsVInst) {
2338 Str << getPredicate() << WidthString;
2339 } else {
2340 Str << WidthString << getPredicate();
2341 }
2342 if (IsVector)
2343 Str << "." << getVecElmtBitsize(Ty);
2344 Str << "\t";
2345 getDest()->emit(Func);
2346 Str << ", ";
2347 getSrc(0)->emit(Func);
2348 }
2349
emit(const Cfg * Func) const2350 template <> void InstARM32Vldr1d::emit(const Cfg *Func) const {
2351 if (!BuildDefs::dump())
2352 return;
2353 Ostream &Str = Func->getContext()->getStrEmit();
2354 assert(getSrcSize() == 1);
2355 assert(getDest()->hasReg());
2356 Variable *Dest = getDest();
2357 Type Ty = Dest->getType();
2358 const bool IsVector = isVectorType(Ty);
2359 const bool IsScalarFloat = isScalarFloatingType(Ty);
2360 const char *ActualOpcode =
2361 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2362 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2363 Str << "\t" << ActualOpcode;
2364 const bool IsVInst = IsVector || IsScalarFloat;
2365 if (IsVInst) {
2366 Str << getPredicate() << WidthString;
2367 } else {
2368 Str << WidthString << getPredicate();
2369 }
2370 if (IsVector)
2371 Str << "." << getVecElmtBitsize(Ty);
2372 Str << "\t";
2373 getDest()->emit(Func);
2374 Str << ", ";
2375 getSrc(0)->emit(Func);
2376 }
2377
emit(const Cfg * Func) const2378 template <> void InstARM32Vldr1q::emit(const Cfg *Func) const {
2379 if (!BuildDefs::dump())
2380 return;
2381 Ostream &Str = Func->getContext()->getStrEmit();
2382 assert(getSrcSize() == 1);
2383 assert(getDest()->hasReg());
2384 Variable *Dest = getDest();
2385 Type Ty = Dest->getType();
2386 const bool IsVector = isVectorType(Ty);
2387 const bool IsScalarFloat = isScalarFloatingType(Ty);
2388 const char *ActualOpcode =
2389 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2390 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2391 Str << "\t" << ActualOpcode;
2392 const bool IsVInst = IsVector || IsScalarFloat;
2393 if (IsVInst) {
2394 Str << getPredicate() << WidthString;
2395 } else {
2396 Str << WidthString << getPredicate();
2397 }
2398 if (IsVector)
2399 Str << "." << getVecElmtBitsize(Ty);
2400 Str << "\t";
2401 getDest()->emit(Func);
2402 Str << ", ";
2403 getSrc(0)->emit(Func);
2404 }
2405
emitIAS(const Cfg * Func) const2406 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
2407 assert(getSrcSize() == 1);
2408 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2409 Variable *Dest = getDest();
2410 const Type DestTy = Dest->getType();
2411 switch (DestTy) {
2412 default:
2413 llvm::report_fatal_error("Ldr on unknown type: " + typeStdString(DestTy));
2414 case IceType_i1:
2415 case IceType_i8:
2416 case IceType_i16:
2417 case IceType_i32:
2418 case IceType_i64:
2419 Asm->ldr(Dest, getSrc(0), getPredicate(), Func->getTarget());
2420 break;
2421 case IceType_f32:
2422 Asm->vldrs(Dest, getSrc(0), getPredicate(), Func->getTarget());
2423 break;
2424 case IceType_f64:
2425 Asm->vldrd(Dest, getSrc(0), getPredicate(), Func->getTarget());
2426 break;
2427 case IceType_v16i8:
2428 case IceType_v8i16:
2429 case IceType_v4i32:
2430 case IceType_v4f32:
2431 case IceType_v16i1:
2432 case IceType_v8i1:
2433 case IceType_v4i1:
2434 Asm->vld1qr(getVecElmtBitsize(DestTy), Dest, getSrc(0), Func->getTarget());
2435 break;
2436 }
2437 }
2438
emitIAS(const Cfg * Func) const2439 template <> void InstARM32Vldr1d::emitIAS(const Cfg *Func) const {
2440 assert(getSrcSize() == 1);
2441 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2442 Variable *Dest = getDest();
2443 Asm->vld1(32, Dest, getSrc(0), Func->getTarget());
2444 }
2445
emitIAS(const Cfg * Func) const2446 template <> void InstARM32Vldr1q::emitIAS(const Cfg *Func) const {
2447 assert(getSrcSize() == 1);
2448 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2449 Variable *Dest = getDest();
2450 Asm->vld1(64, Dest, getSrc(0), Func->getTarget());
2451 }
2452
emit(const Cfg * Func) const2453 template <> void InstARM32Ldrex::emit(const Cfg *Func) const {
2454 if (!BuildDefs::dump())
2455 return;
2456 Ostream &Str = Func->getContext()->getStrEmit();
2457 assert(getSrcSize() == 1);
2458 assert(getDest()->hasReg());
2459 Variable *Dest = getDest();
2460 Type DestTy = Dest->getType();
2461 assert(isScalarIntegerType(DestTy));
2462 const char *WidthString = getWidthString(DestTy);
2463 Str << "\t" << Opcode << WidthString << getPredicate() << "\t";
2464 getDest()->emit(Func);
2465 Str << ", ";
2466 getSrc(0)->emit(Func);
2467 }
2468
emitIAS(const Cfg * Func) const2469 template <> void InstARM32Ldrex::emitIAS(const Cfg *Func) const {
2470 assert(getSrcSize() == 1);
2471 assert(getDest()->hasReg());
2472 Variable *Dest = getDest();
2473 assert(isScalarIntegerType(Dest->getType()));
2474 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2475 Asm->ldrex(Dest, getSrc(0), getPredicate(), Func->getTarget());
2476 if (Asm->needsTextFixup())
2477 emitUsingTextFixup(Func);
2478 }
2479
2480 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2481 void InstARM32TwoAddrGPR<K>::emitIAS(const Cfg *Func) const {
2482 emitUsingTextFixup(Func);
2483 }
2484
2485 template <InstARM32::InstKindARM32 K, bool Nws>
emitIAS(const Cfg * Func) const2486 void InstARM32UnaryopGPR<K, Nws>::emitIAS(const Cfg *Func) const {
2487 emitUsingTextFixup(Func);
2488 }
2489
emitIAS(const Cfg * Func) const2490 template <> void InstARM32Rbit::emitIAS(const Cfg *Func) const {
2491 assert(getSrcSize() == 1);
2492 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2493 Asm->rbit(getDest(), getSrc(0), getPredicate());
2494 if (Asm->needsTextFixup())
2495 emitUsingTextFixup(Func);
2496 }
2497
emitIAS(const Cfg * Func) const2498 template <> void InstARM32Rev::emitIAS(const Cfg *Func) const {
2499 assert(getSrcSize() == 1);
2500 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2501 Asm->rev(getDest(), getSrc(0), getPredicate());
2502 if (Asm->needsTextFixup())
2503 emitUsingTextFixup(Func);
2504 }
2505
emit(const Cfg * Func) const2506 template <> void InstARM32Movw::emit(const Cfg *Func) const {
2507 if (!BuildDefs::dump())
2508 return;
2509 Ostream &Str = Func->getContext()->getStrEmit();
2510 assert(getSrcSize() == 1);
2511 Str << "\t" << Opcode << getPredicate() << "\t";
2512 getDest()->emit(Func);
2513 Str << ", ";
2514 auto *Src0 = llvm::cast<Constant>(getSrc(0));
2515 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) {
2516 Str << "#:lower16:";
2517 CR->emitWithoutPrefix(Func->getTarget());
2518 if (getFlags().getUseNonsfi()) {
2519 Str << " - .";
2520 }
2521 } else {
2522 Src0->emit(Func);
2523 }
2524 }
2525
emitIAS(const Cfg * Func) const2526 template <> void InstARM32Movw::emitIAS(const Cfg *Func) const {
2527 assert(getSrcSize() == 1);
2528 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2529 Asm->movw(getDest(), getSrc(0), getPredicate());
2530 if (Asm->needsTextFixup())
2531 emitUsingTextFixup(Func);
2532 }
2533
emit(const Cfg * Func) const2534 template <> void InstARM32Movt::emit(const Cfg *Func) const {
2535 if (!BuildDefs::dump())
2536 return;
2537 Ostream &Str = Func->getContext()->getStrEmit();
2538 assert(getSrcSize() == 2);
2539 Variable *Dest = getDest();
2540 auto *Src1 = llvm::cast<Constant>(getSrc(1));
2541 Str << "\t" << Opcode << getPredicate() << "\t";
2542 Dest->emit(Func);
2543 Str << ", ";
2544 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) {
2545 Str << "#:upper16:";
2546 CR->emitWithoutPrefix(Func->getTarget());
2547 if (getFlags().getUseNonsfi()) {
2548 Str << " - .";
2549 }
2550 } else {
2551 Src1->emit(Func);
2552 }
2553 }
2554
emitIAS(const Cfg * Func) const2555 template <> void InstARM32Movt::emitIAS(const Cfg *Func) const {
2556 assert(getSrcSize() == 2);
2557 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2558 Asm->movt(getDest(), getSrc(1), getPredicate());
2559 if (Asm->needsTextFixup())
2560 emitUsingTextFixup(Func);
2561 }
2562
emitIAS(const Cfg * Func) const2563 template <> void InstARM32Clz::emitIAS(const Cfg *Func) const {
2564 assert(getSrcSize() == 1);
2565 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2566 Asm->clz(getDest(), getSrc(0), getPredicate());
2567 if (Asm->needsTextFixup())
2568 emitUsingTextFixup(Func);
2569 }
2570
emitIAS(const Cfg * Func) const2571 template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const {
2572 assert(getSrcSize() == 1);
2573 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2574 Asm->mvn(getDest(), getSrc(0), getPredicate());
2575 if (Asm->needsTextFixup())
2576 emitUsingTextFixup(Func);
2577 }
2578
emitIAS(const Cfg * Func) const2579 template <> void InstARM32Sxt::emitIAS(const Cfg *Func) const {
2580 assert(getSrcSize() == 1);
2581 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2582 Asm->sxt(getDest(), getSrc(0), getPredicate());
2583 if (Asm->needsTextFixup())
2584 emitUsingTextFixup(Func);
2585 }
2586
emitIAS(const Cfg * Func) const2587 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
2588 assert(getSrcSize() == 1);
2589 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2590 Asm->uxt(getDest(), getSrc(0), getPredicate());
2591 if (Asm->needsTextFixup())
2592 emitUsingTextFixup(Func);
2593 }
2594
2595 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2596 void InstARM32UnaryopFP<K>::emitIAS(const Cfg *Func) const {
2597 emitUsingTextFixup(Func);
2598 }
2599
2600 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2601 void InstARM32UnaryopSignAwareFP<K>::emitIAS(const Cfg *Func) const {
2602 InstARM32::emitUsingTextFixup(Func);
2603 }
2604
emitIAS(const Cfg * Func) const2605 template <> void InstARM32Vsqrt::emitIAS(const Cfg *Func) const {
2606 assert(getSrcSize() == 1);
2607 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2608 const Operand *Dest = getDest();
2609 switch (Dest->getType()) {
2610 case IceType_f32:
2611 Asm->vsqrts(Dest, getSrc(0), getPredicate());
2612 break;
2613 case IceType_f64:
2614 Asm->vsqrtd(Dest, getSrc(0), getPredicate());
2615 break;
2616 default:
2617 llvm::report_fatal_error("Vsqrt of non-floating type");
2618 }
2619 if (Asm->needsTextFixup())
2620 emitUsingTextFixup(Func);
2621 }
2622
getGPROpcode() const2623 const char *InstARM32Pop::getGPROpcode() const { return "pop"; }
2624
getSRegOpcode() const2625 const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; }
2626
getStackReg(SizeT Index) const2627 Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; }
2628
getNumStackRegs() const2629 SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); }
2630
emitSingleGPR(const Cfg * Func,const EmitForm Form,const Variable * Reg) const2631 void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form,
2632 const Variable *Reg) const {
2633 switch (Form) {
2634 case Emit_Text:
2635 emitGPRsAsText(Func);
2636 return;
2637 case Emit_Binary:
2638 Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL);
2639 return;
2640 }
2641 }
2642
emitMultipleGPRs(const Cfg * Func,const EmitForm Form,IValueT Registers) const2643 void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
2644 IValueT Registers) const {
2645 switch (Form) {
2646 case Emit_Text:
2647 emitGPRsAsText(Func);
2648 return;
2649 case Emit_Binary:
2650 Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers,
2651 CondARM32::AL);
2652 return;
2653 }
2654 }
2655
emitSRegs(const Cfg * Func,const EmitForm Form,const Variable * BaseReg,SizeT RegCount) const2656 void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form,
2657 const Variable *BaseReg, SizeT RegCount) const {
2658 switch (Form) {
2659 case Emit_Text:
2660 emitSRegsAsText(Func, BaseReg, RegCount);
2661 return;
2662 case Emit_Binary:
2663 Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount,
2664 CondARM32::AL);
2665 return;
2666 }
2667 }
2668
getGPROpcode() const2669 const char *InstARM32Push::getGPROpcode() const { return "push"; }
2670
getSRegOpcode() const2671 const char *InstARM32Push::getSRegOpcode() const { return "vpush"; }
2672
getStackReg(SizeT Index) const2673 Variable *InstARM32Push::getStackReg(SizeT Index) const {
2674 return llvm::cast<Variable>(getSrc(Index));
2675 }
2676
getNumStackRegs() const2677 SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); }
2678
emitSingleGPR(const Cfg * Func,const EmitForm Form,const Variable * Reg) const2679 void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form,
2680 const Variable *Reg) const {
2681 switch (Form) {
2682 case Emit_Text:
2683 emitGPRsAsText(Func);
2684 return;
2685 case Emit_Binary:
2686 Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL);
2687 return;
2688 }
2689 }
2690
emitMultipleGPRs(const Cfg * Func,const EmitForm Form,IValueT Registers) const2691 void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
2692 IValueT Registers) const {
2693 switch (Form) {
2694 case Emit_Text:
2695 emitGPRsAsText(Func);
2696 return;
2697 case Emit_Binary:
2698 Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers,
2699 CondARM32::AL);
2700 return;
2701 }
2702 }
2703
emitSRegs(const Cfg * Func,const EmitForm Form,const Variable * BaseReg,SizeT RegCount) const2704 void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form,
2705 const Variable *BaseReg, SizeT RegCount) const {
2706 switch (Form) {
2707 case Emit_Text:
2708 emitSRegsAsText(Func, BaseReg, RegCount);
2709 return;
2710 case Emit_Binary:
2711 Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount,
2712 CondARM32::AL);
2713 return;
2714 }
2715 }
2716
emit(const Cfg * Func) const2717 void InstARM32Ret::emit(const Cfg *Func) const {
2718 if (!BuildDefs::dump())
2719 return;
2720 assert(getSrcSize() > 0);
2721 auto *LR = llvm::cast<Variable>(getSrc(0));
2722 assert(LR->hasReg());
2723 assert(LR->getRegNum() == RegARM32::Reg_lr);
2724 Ostream &Str = Func->getContext()->getStrEmit();
2725 Str << "\t"
2726 "bx"
2727 "\t";
2728 LR->emit(Func);
2729 }
2730
emitIAS(const Cfg * Func) const2731 void InstARM32Ret::emitIAS(const Cfg *Func) const {
2732 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2733 Asm->bx(RegARM32::Encoded_Reg_lr);
2734 if (Asm->needsTextFixup())
2735 emitUsingTextFixup(Func);
2736 }
2737
dump(const Cfg * Func) const2738 void InstARM32Ret::dump(const Cfg *Func) const {
2739 if (!BuildDefs::dump())
2740 return;
2741 Ostream &Str = Func->getContext()->getStrDump();
2742 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType());
2743 Str << "ret." << Ty << " ";
2744 dumpSources(Func);
2745 }
2746
emit(const Cfg * Func) const2747 void InstARM32Str::emit(const Cfg *Func) const {
2748 if (!BuildDefs::dump())
2749 return;
2750 Ostream &Str = Func->getContext()->getStrEmit();
2751 assert(getSrcSize() == 2);
2752 Type Ty = getSrc(0)->getType();
2753 const bool IsVectorStore = isVectorType(Ty);
2754 const bool IsScalarFloat = isScalarFloatingType(Ty);
2755 const char *Opcode =
2756 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str");
2757 Str << "\t" << Opcode;
2758 const bool IsVInst = IsVectorStore || IsScalarFloat;
2759 if (IsVInst) {
2760 Str << getPredicate() << getWidthString(Ty);
2761 } else {
2762 Str << getWidthString(Ty) << getPredicate();
2763 }
2764 if (IsVectorStore)
2765 Str << "." << getVecElmtBitsize(Ty);
2766 Str << "\t";
2767 getSrc(0)->emit(Func);
2768 Str << ", ";
2769 getSrc(1)->emit(Func);
2770 }
2771
emitIAS(const Cfg * Func) const2772 void InstARM32Str::emitIAS(const Cfg *Func) const {
2773 assert(getSrcSize() == 2);
2774 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2775 const Operand *Src0 = getSrc(0);
2776 const Operand *Src1 = getSrc(1);
2777 Type Ty = Src0->getType();
2778 switch (Ty) {
2779 default:
2780 llvm::report_fatal_error("Str on unknown type: " + typeStdString(Ty));
2781 case IceType_i1:
2782 case IceType_i8:
2783 case IceType_i16:
2784 case IceType_i32:
2785 case IceType_i64:
2786 Asm->str(Src0, Src1, getPredicate(), Func->getTarget());
2787 break;
2788 case IceType_f32:
2789 Asm->vstrs(Src0, Src1, getPredicate(), Func->getTarget());
2790 break;
2791 case IceType_f64:
2792 Asm->vstrd(Src0, Src1, getPredicate(), Func->getTarget());
2793 break;
2794 case IceType_v16i8:
2795 case IceType_v8i16:
2796 case IceType_v4i32:
2797 case IceType_v4f32:
2798 case IceType_v16i1:
2799 case IceType_v8i1:
2800 case IceType_v4i1:
2801 Asm->vst1qr(getVecElmtBitsize(Ty), Src0, Src1, Func->getTarget());
2802 break;
2803 }
2804 }
2805
dump(const Cfg * Func) const2806 void InstARM32Str::dump(const Cfg *Func) const {
2807 if (!BuildDefs::dump())
2808 return;
2809 Ostream &Str = Func->getContext()->getStrDump();
2810 Type Ty = getSrc(0)->getType();
2811 dumpOpcodePred(Str, "str", Ty);
2812 Str << " ";
2813 getSrc(1)->dump(Func);
2814 Str << ", ";
2815 getSrc(0)->dump(Func);
2816 }
2817
emit(const Cfg * Func) const2818 void InstARM32Strex::emit(const Cfg *Func) const {
2819 if (!BuildDefs::dump())
2820 return;
2821 assert(getSrcSize() == 2);
2822 Type Ty = getSrc(0)->getType();
2823 assert(isScalarIntegerType(Ty));
2824 Variable *Dest = getDest();
2825 Ostream &Str = Func->getContext()->getStrEmit();
2826 static constexpr char Opcode[] = "strex";
2827 const char *WidthString = getWidthString(Ty);
2828 Str << "\t" << Opcode << WidthString << getPredicate() << "\t";
2829 Dest->emit(Func);
2830 Str << ", ";
2831 emitSources(Func);
2832 }
2833
emitIAS(const Cfg * Func) const2834 void InstARM32Strex::emitIAS(const Cfg *Func) const {
2835 assert(getSrcSize() == 2);
2836 const Operand *Src0 = getSrc(0);
2837 assert(isScalarIntegerType(Src0->getType()));
2838 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2839 Asm->strex(Dest, Src0, getSrc(1), getPredicate(), Func->getTarget());
2840 if (Asm->needsTextFixup())
2841 emitUsingTextFixup(Func);
2842 }
2843
dump(const Cfg * Func) const2844 void InstARM32Strex::dump(const Cfg *Func) const {
2845 if (!BuildDefs::dump())
2846 return;
2847 Ostream &Str = Func->getContext()->getStrDump();
2848 Variable *Dest = getDest();
2849 Dest->dump(Func);
2850 Str << " = ";
2851 Type Ty = getSrc(0)->getType();
2852 dumpOpcodePred(Str, "strex", Ty);
2853 Str << " ";
2854 getSrc(1)->dump(Func);
2855 Str << ", ";
2856 getSrc(0)->dump(Func);
2857 }
2858
emit(const Cfg * Func) const2859 void InstARM32Vstr1::emit(const Cfg *Func) const {
2860 if (!BuildDefs::dump())
2861 return;
2862 Ostream &Str = Func->getContext()->getStrEmit();
2863 assert(getSrcSize() == 2);
2864 Type Ty = getSrc(0)->getType();
2865 const bool IsVectorStore = isVectorType(Ty);
2866 const bool IsScalarFloat = isScalarFloatingType(Ty);
2867 const char *Opcode =
2868 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str");
2869 Str << "\t" << Opcode;
2870 const bool IsVInst = IsVectorStore || IsScalarFloat;
2871 if (IsVInst) {
2872 Str << getPredicate() << getWidthString(Ty);
2873 } else {
2874 Str << getWidthString(Ty) << getPredicate();
2875 }
2876 if (IsVectorStore)
2877 Str << "." << getVecElmtBitsize(Ty);
2878 Str << "\t";
2879 getSrc(0)->emit(Func);
2880 Str << ", ";
2881 getSrc(1)->emit(Func);
2882 }
2883
emitIAS(const Cfg * Func) const2884 void InstARM32Vstr1::emitIAS(const Cfg *Func) const {
2885 assert(getSrcSize() == 2);
2886 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2887 const Operand *Src0 = getSrc(0);
2888 const Operand *Src1 = getSrc(1);
2889 Asm->vst1(Size, Src0, Src1, Func->getTarget());
2890 }
2891
dump(const Cfg * Func) const2892 void InstARM32Vstr1::dump(const Cfg *Func) const {
2893 if (!BuildDefs::dump())
2894 return;
2895 Ostream &Str = Func->getContext()->getStrDump();
2896 Type Ty = getSrc(0)->getType();
2897 dumpOpcodePred(Str, "str", Ty);
2898 Str << " ";
2899 getSrc(1)->dump(Func);
2900 Str << ", ";
2901 getSrc(0)->dump(Func);
2902 }
2903
emit(const Cfg * Func) const2904 void InstARM32Vdup::emit(const Cfg *Func) const {
2905 if (!BuildDefs::dump())
2906 return;
2907 Ostream &Str = Func->getContext()->getStrEmit();
2908 assert(getSrcSize() == 2);
2909 Type Ty = getSrc(0)->getType();
2910 const char *Opcode = "vdup";
2911 Str << "\t" << Opcode;
2912 Str << getPredicate() << "." << getWidthString(Ty) << getVecElmtBitsize(Ty);
2913 Str << "\t";
2914 getSrc(0)->emit(Func);
2915 Str << ", ";
2916 getSrc(1)->emit(Func);
2917 Str << ", " << Idx;
2918 }
2919
emitIAS(const Cfg * Func) const2920 void InstARM32Vdup::emitIAS(const Cfg *Func) const {
2921 assert(getSrcSize() == 1);
2922 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2923 const Operand *Dest = getDest();
2924 const Operand *Src = getSrc(0);
2925 Type DestTy = Dest->getType();
2926 Asm->vdup(typeElementType(DestTy), Dest, Src, Idx);
2927 }
2928
dump(const Cfg * Func) const2929 void InstARM32Vdup::dump(const Cfg *Func) const {
2930 if (!BuildDefs::dump())
2931 return;
2932 Ostream &Str = Func->getContext()->getStrDump();
2933 dumpDest(Func);
2934 Str << " = ";
2935 dumpOpcodePred(Str, "vdup", getDest()->getType());
2936 Str << " ";
2937 dumpSources(Func);
2938 Str << ", " << Idx;
2939 }
2940
emit(const Cfg * Func) const2941 void InstARM32Trap::emit(const Cfg *Func) const {
2942 if (!BuildDefs::dump())
2943 return;
2944 Ostream &Str = Func->getContext()->getStrEmit();
2945 assert(getSrcSize() == 0);
2946 // There isn't a mnemonic for the special NaCl Trap encoding, so dump
2947 // the raw bytes.
2948 Str << "\t.long 0x";
2949 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2950 for (uint8_t I : Asm->getNonExecBundlePadding()) {
2951 Str.write_hex(I);
2952 }
2953 }
2954
emitIAS(const Cfg * Func) const2955 void InstARM32Trap::emitIAS(const Cfg *Func) const {
2956 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2957 Asm->trap();
2958 assert(!Asm->needsTextFixup());
2959 }
2960
dump(const Cfg * Func) const2961 void InstARM32Trap::dump(const Cfg *Func) const {
2962 if (!BuildDefs::dump())
2963 return;
2964 Ostream &Str = Func->getContext()->getStrDump();
2965 Str << "trap";
2966 }
2967
emit(const Cfg * Func) const2968 void InstARM32Umull::emit(const Cfg *Func) const {
2969 if (!BuildDefs::dump())
2970 return;
2971 Ostream &Str = Func->getContext()->getStrEmit();
2972 assert(getSrcSize() == 2);
2973 assert(getDest()->hasReg());
2974 Str << "\t"
2975 "umull" << getPredicate() << "\t";
2976 getDest()->emit(Func);
2977 Str << ", ";
2978 DestHi->emit(Func);
2979 Str << ", ";
2980 getSrc(0)->emit(Func);
2981 Str << ", ";
2982 getSrc(1)->emit(Func);
2983 }
2984
emitIAS(const Cfg * Func) const2985 void InstARM32Umull::emitIAS(const Cfg *Func) const {
2986 assert(getSrcSize() == 2);
2987 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2988 Asm->umull(getDest(), DestHi, getSrc(0), getSrc(1), getPredicate());
2989 if (Asm->needsTextFixup())
2990 emitUsingTextFixup(Func);
2991 }
2992
dump(const Cfg * Func) const2993 void InstARM32Umull::dump(const Cfg *Func) const {
2994 if (!BuildDefs::dump())
2995 return;
2996 Ostream &Str = Func->getContext()->getStrDump();
2997 dumpDest(Func);
2998 Str << " = ";
2999 dumpOpcodePred(Str, "umull", getDest()->getType());
3000 Str << " ";
3001 dumpSources(Func);
3002 }
3003
3004 namespace {
vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant)3005 const char *vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant) {
3006 switch (Variant) {
3007 case InstARM32Vcvt::S2si:
3008 return ".s32.f32";
3009 case InstARM32Vcvt::S2ui:
3010 return ".u32.f32";
3011 case InstARM32Vcvt::Si2s:
3012 return ".f32.s32";
3013 case InstARM32Vcvt::Ui2s:
3014 return ".f32.u32";
3015 case InstARM32Vcvt::D2si:
3016 return ".s32.f64";
3017 case InstARM32Vcvt::D2ui:
3018 return ".u32.f64";
3019 case InstARM32Vcvt::Si2d:
3020 return ".f64.s32";
3021 case InstARM32Vcvt::Ui2d:
3022 return ".f64.u32";
3023 case InstARM32Vcvt::S2d:
3024 return ".f64.f32";
3025 case InstARM32Vcvt::D2s:
3026 return ".f32.f64";
3027 case InstARM32Vcvt::Vs2si:
3028 return ".s32.f32";
3029 case InstARM32Vcvt::Vs2ui:
3030 return ".u32.f32";
3031 case InstARM32Vcvt::Vsi2s:
3032 return ".f32.s32";
3033 case InstARM32Vcvt::Vui2s:
3034 return ".f32.u32";
3035 }
3036 llvm::report_fatal_error("Invalid VcvtVariant enum.");
3037 }
3038 } // end of anonymous namespace
3039
emit(const Cfg * Func) const3040 void InstARM32Vcvt::emit(const Cfg *Func) const {
3041 if (!BuildDefs::dump())
3042 return;
3043 Ostream &Str = Func->getContext()->getStrEmit();
3044 assert(getSrcSize() == 1);
3045 assert(getDest()->hasReg());
3046 Str << "\t"
3047 "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << "\t";
3048 getDest()->emit(Func);
3049 Str << ", ";
3050 getSrc(0)->emit(Func);
3051 }
3052
emitIAS(const Cfg * Func) const3053 void InstARM32Vcvt::emitIAS(const Cfg *Func) const {
3054 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3055 switch (Variant) {
3056 case S2si:
3057 Asm->vcvtis(getDest(), getSrc(0), getPredicate());
3058 break;
3059 case S2ui:
3060 Asm->vcvtus(getDest(), getSrc(0), getPredicate());
3061 break;
3062 case Si2s:
3063 Asm->vcvtsi(getDest(), getSrc(0), getPredicate());
3064 break;
3065 case Ui2s:
3066 Asm->vcvtsu(getDest(), getSrc(0), getPredicate());
3067 break;
3068 case D2si:
3069 Asm->vcvtid(getDest(), getSrc(0), getPredicate());
3070 break;
3071 case D2ui:
3072 Asm->vcvtud(getDest(), getSrc(0), getPredicate());
3073 break;
3074 case Si2d:
3075 Asm->vcvtdi(getDest(), getSrc(0), getPredicate());
3076 break;
3077 case Ui2d:
3078 Asm->vcvtdu(getDest(), getSrc(0), getPredicate());
3079 break;
3080 case S2d:
3081 Asm->vcvtds(getDest(), getSrc(0), getPredicate());
3082 break;
3083 case D2s:
3084 Asm->vcvtsd(getDest(), getSrc(0), getPredicate());
3085 break;
3086 case Vs2si:
3087 Asm->vcvtqsi(getDest(), getSrc(0));
3088 break;
3089 case Vs2ui:
3090 Asm->vcvtqsu(getDest(), getSrc(0));
3091 break;
3092 case Vsi2s:
3093 Asm->vcvtqis(getDest(), getSrc(0));
3094 break;
3095 case Vui2s:
3096 Asm->vcvtqus(getDest(), getSrc(0));
3097 break;
3098 }
3099 assert(!Asm->needsTextFixup());
3100 }
3101
dump(const Cfg * Func) const3102 void InstARM32Vcvt::dump(const Cfg *Func) const {
3103 if (!BuildDefs::dump())
3104 return;
3105 Ostream &Str = Func->getContext()->getStrDump();
3106 dumpDest(Func);
3107 Str << " = "
3108 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " ";
3109 dumpSources(Func);
3110 }
3111
emit(const Cfg * Func) const3112 void InstARM32Vcmp::emit(const Cfg *Func) const {
3113 if (!BuildDefs::dump())
3114 return;
3115 Ostream &Str = Func->getContext()->getStrEmit();
3116 assert(getSrcSize() == 2);
3117 Str << "\t"
3118 "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType())
3119 << "\t";
3120 getSrc(0)->emit(Func);
3121 Str << ", ";
3122 getSrc(1)->emit(Func);
3123 }
3124
emitIAS(const Cfg * Func) const3125 void InstARM32Vcmp::emitIAS(const Cfg *Func) const {
3126 assert(getSrcSize() == 2);
3127 const Operand *Src0 = getSrc(0);
3128 const Type Ty = Src0->getType();
3129 const Operand *Src1 = getSrc(1);
3130 const CondARM32::Cond Cond = getPredicate();
3131 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3132 if (llvm::isa<OperandARM32FlexFpZero>(Src1)) {
3133 switch (Ty) {
3134 case IceType_f32:
3135 Asm->vcmpsz(Src0, Cond);
3136 break;
3137 case IceType_f64:
3138 Asm->vcmpdz(Src0, Cond);
3139 break;
3140 default:
3141 llvm::report_fatal_error("Vcvt on non floating value");
3142 }
3143 } else {
3144 switch (Ty) {
3145 case IceType_f32:
3146 Asm->vcmps(Src0, Src1, Cond);
3147 break;
3148 case IceType_f64:
3149 Asm->vcmpd(Src0, Src1, Cond);
3150 break;
3151 default:
3152 llvm::report_fatal_error("Vcvt on non floating value");
3153 }
3154 }
3155 assert(!Asm->needsTextFixup());
3156 }
3157
dump(const Cfg * Func) const3158 void InstARM32Vcmp::dump(const Cfg *Func) const {
3159 if (!BuildDefs::dump())
3160 return;
3161 Ostream &Str = Func->getContext()->getStrDump();
3162 Str << "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType());
3163 dumpSources(Func);
3164 }
3165
emit(const Cfg * Func) const3166 void InstARM32Vmrs::emit(const Cfg *Func) const {
3167 if (!BuildDefs::dump())
3168 return;
3169 Ostream &Str = Func->getContext()->getStrEmit();
3170 assert(getSrcSize() == 0);
3171 Str << "\t"
3172 "vmrs" << getPredicate() << "\t"
3173 "APSR_nzcv"
3174 ", "
3175 "FPSCR";
3176 }
3177
emitIAS(const Cfg * Func) const3178 void InstARM32Vmrs::emitIAS(const Cfg *Func) const {
3179 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3180 Asm->vmrsAPSR_nzcv(getPredicate());
3181 assert(!Asm->needsTextFixup());
3182 }
3183
dump(const Cfg * Func) const3184 void InstARM32Vmrs::dump(const Cfg *Func) const {
3185 if (!BuildDefs::dump())
3186 return;
3187 Ostream &Str = Func->getContext()->getStrDump();
3188 Str << "APSR{n,z,v,c} = vmrs" << getPredicate() << "\t"
3189 "FPSCR{n,z,c,v}";
3190 }
3191
emit(const Cfg * Func) const3192 void InstARM32Vabs::emit(const Cfg *Func) const {
3193 if (!BuildDefs::dump())
3194 return;
3195 Ostream &Str = Func->getContext()->getStrEmit();
3196 assert(getSrcSize() == 1);
3197 Str << "\t"
3198 "vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType())
3199 << "\t";
3200 getDest()->emit(Func);
3201 Str << ", ";
3202 getSrc(0)->emit(Func);
3203 }
3204
emitIAS(const Cfg * Func) const3205 void InstARM32Vabs::emitIAS(const Cfg *Func) const {
3206 assert(getSrcSize() == 1);
3207 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3208 const Variable *Dest = getDest();
3209 switch (Dest->getType()) {
3210 default:
3211 llvm::report_fatal_error("fabs not defined on type " +
3212 typeStdString(Dest->getType()));
3213 case IceType_f32:
3214 Asm->vabss(Dest, getSrc(0), getPredicate());
3215 break;
3216 case IceType_f64:
3217 Asm->vabsd(Dest, getSrc(0), getPredicate());
3218 break;
3219 case IceType_v4f32:
3220 assert(CondARM32::isUnconditional(getPredicate()) &&
3221 "fabs must be unconditional");
3222 Asm->vabsq(Dest, getSrc(0));
3223 }
3224 assert(!Asm->needsTextFixup());
3225 }
3226
dump(const Cfg * Func) const3227 void InstARM32Vabs::dump(const Cfg *Func) const {
3228 if (!BuildDefs::dump())
3229 return;
3230 Ostream &Str = Func->getContext()->getStrDump();
3231 dumpDest(Func);
3232 Str << " = vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType());
3233 }
3234
emit(const Cfg * Func) const3235 void InstARM32Dmb::emit(const Cfg *Func) const {
3236 if (!BuildDefs::dump())
3237 return;
3238 Ostream &Str = Func->getContext()->getStrEmit();
3239 assert(getSrcSize() == 0);
3240 Str << "\t"
3241 "dmb"
3242 "\t"
3243 "sy";
3244 }
3245
emitIAS(const Cfg * Func) const3246 void InstARM32Dmb::emitIAS(const Cfg *Func) const {
3247 assert(getSrcSize() == 0);
3248 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3249 constexpr ARM32::IValueT SyOption = 0xF; // i.e. 1111
3250 Asm->dmb(SyOption);
3251 if (Asm->needsTextFixup())
3252 emitUsingTextFixup(Func);
3253 }
3254
dump(const Cfg * Func) const3255 void InstARM32Dmb::dump(const Cfg *Func) const {
3256 if (!BuildDefs::dump())
3257 return;
3258 Func->getContext()->getStrDump() << "dmb\t"
3259 "sy";
3260 }
3261
emit(const Cfg * Func) const3262 void InstARM32Nop::emit(const Cfg *Func) const {
3263 if (!BuildDefs::dump())
3264 return;
3265 assert(getSrcSize() == 0);
3266 Func->getContext()->getStrEmit() << "\t"
3267 << "nop";
3268 }
3269
emitIAS(const Cfg * Func) const3270 void InstARM32Nop::emitIAS(const Cfg *Func) const {
3271 assert(getSrcSize() == 0);
3272 Func->getAssembler<ARM32::AssemblerARM32>()->nop();
3273 }
3274
dump(const Cfg * Func) const3275 void InstARM32Nop::dump(const Cfg *Func) const {
3276 if (!BuildDefs::dump())
3277 return;
3278 assert(getSrcSize() == 0);
3279 Func->getContext()->getStrDump() << "nop";
3280 }
3281
emit(const Cfg * Func) const3282 void OperandARM32Mem::emit(const Cfg *Func) const {
3283 if (!BuildDefs::dump())
3284 return;
3285 Ostream &Str = Func->getContext()->getStrEmit();
3286 Str << "[";
3287 getBase()->emit(Func);
3288 switch (getAddrMode()) {
3289 case PostIndex:
3290 case NegPostIndex:
3291 Str << "]";
3292 break;
3293 default:
3294 break;
3295 }
3296 if (isRegReg()) {
3297 Str << ", ";
3298 if (isNegAddrMode()) {
3299 Str << "-";
3300 }
3301 getIndex()->emit(Func);
3302 if (getShiftOp() != kNoShift) {
3303 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #"
3304 << getShiftAmt();
3305 }
3306 } else {
3307 ConstantInteger32 *Offset = getOffset();
3308 if (Offset && Offset->getValue() != 0) {
3309 Str << ", ";
3310 Offset->emit(Func);
3311 }
3312 }
3313 switch (getAddrMode()) {
3314 case Offset:
3315 case NegOffset:
3316 Str << "]";
3317 break;
3318 case PreIndex:
3319 case NegPreIndex:
3320 Str << "]!";
3321 break;
3322 case PostIndex:
3323 case NegPostIndex:
3324 // Brace is already closed off.
3325 break;
3326 }
3327 }
3328
dump(const Cfg * Func,Ostream & Str) const3329 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const {
3330 if (!BuildDefs::dump())
3331 return;
3332 Str << "[";
3333 if (Func)
3334 getBase()->dump(Func);
3335 else
3336 getBase()->dump(Str);
3337 Str << ", ";
3338 if (isRegReg()) {
3339 if (isNegAddrMode()) {
3340 Str << "-";
3341 }
3342 if (Func)
3343 getIndex()->dump(Func);
3344 else
3345 getIndex()->dump(Str);
3346 if (getShiftOp() != kNoShift) {
3347 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #"
3348 << getShiftAmt();
3349 }
3350 } else {
3351 getOffset()->dump(Func, Str);
3352 }
3353 Str << "] AddrMode==" << getAddrMode();
3354 }
3355
emit(const Cfg * Func) const3356 void OperandARM32ShAmtImm::emit(const Cfg *Func) const { ShAmt->emit(Func); }
3357
dump(const Cfg *,Ostream & Str) const3358 void OperandARM32ShAmtImm::dump(const Cfg *, Ostream &Str) const {
3359 ShAmt->dump(Str);
3360 }
3361
create(Cfg * Func,Type Ty,uint32_t Imm,uint32_t RotateAmt)3362 OperandARM32FlexImm *OperandARM32FlexImm::create(Cfg *Func, Type Ty,
3363 uint32_t Imm,
3364 uint32_t RotateAmt) {
3365 // The assembler wants the smallest rotation. Rotate if needed. Note: Imm is
3366 // an 8-bit value.
3367 assert(Utils::IsUint(8, Imm) &&
3368 "Flex immediates can only be defined on 8-bit immediates");
3369 while ((Imm & 0x03) == 0 && RotateAmt > 0) {
3370 --RotateAmt;
3371 Imm = Imm >> 2;
3372 }
3373 return new (Func->allocate<OperandARM32FlexImm>())
3374 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt);
3375 }
3376
emit(const Cfg * Func) const3377 void OperandARM32FlexImm::emit(const Cfg *Func) const {
3378 if (!BuildDefs::dump())
3379 return;
3380 Ostream &Str = Func->getContext()->getStrEmit();
3381 uint32_t Imm = getImm();
3382 uint32_t RotateAmt = getRotateAmt();
3383 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt);
3384 }
3385
dump(const Cfg *,Ostream & Str) const3386 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const {
3387 if (!BuildDefs::dump())
3388 return;
3389 uint32_t Imm = getImm();
3390 uint32_t RotateAmt = getRotateAmt();
3391 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")";
3392 }
3393
3394 namespace {
3395 static constexpr uint32_t a = 0x80;
3396 static constexpr uint32_t b = 0x40;
3397 static constexpr uint32_t cdefgh = 0x3F;
3398 static constexpr uint32_t AllowedBits = a | b | cdefgh;
3399 static_assert(AllowedBits == 0xFF,
3400 "Invalid mask for f32/f64 constant rematerialization.");
3401
3402 // There's no loss in always returning the modified immediate as float.
3403 // TODO(jpp): returning a double causes problems when outputting the constants
3404 // for filetype=asm. Why?
materializeFloatImmediate(uint32_t ModifiedImm)3405 float materializeFloatImmediate(uint32_t ModifiedImm) {
3406 const uint32_t Ret = ((ModifiedImm & a) ? 0x80000000 : 0) |
3407 ((ModifiedImm & b) ? 0x3E000000 : 0x40000000) |
3408 ((ModifiedImm & cdefgh) << 19);
3409 return Utils::bitCopy<float>(Ret);
3410 }
3411
3412 } // end of anonymous namespace
3413
emit(const Cfg * Func) const3414 void OperandARM32FlexFpImm::emit(const Cfg *Func) const {
3415 if (!BuildDefs::dump())
3416 return;
3417 Ostream &Str = Func->getContext()->getStrEmit();
3418 switch (Ty) {
3419 default:
3420 llvm::report_fatal_error("Invalid flex fp imm type.");
3421 case IceType_f64:
3422 case IceType_f32:
3423 Str << "#" << materializeFloatImmediate(ModifiedImm)
3424 << " @ Modified: " << ModifiedImm;
3425 break;
3426 }
3427 }
3428
dump(const Cfg *,Ostream & Str) const3429 void OperandARM32FlexFpImm::dump(const Cfg * /*Func*/, Ostream &Str) const {
3430 if (!BuildDefs::dump())
3431 return;
3432 Str << "#" << materializeFloatImmediate(ModifiedImm) << getFpWidthString(Ty);
3433 }
3434
emit(const Cfg * Func) const3435 void OperandARM32FlexFpZero::emit(const Cfg *Func) const {
3436 if (!BuildDefs::dump())
3437 return;
3438 Ostream &Str = Func->getContext()->getStrEmit();
3439 switch (Ty) {
3440 default:
3441 llvm::report_fatal_error("Invalid flex fp imm type.");
3442 case IceType_f64:
3443 case IceType_f32:
3444 Str << "#0.0";
3445 }
3446 }
3447
dump(const Cfg *,Ostream & Str) const3448 void OperandARM32FlexFpZero::dump(const Cfg * /*Func*/, Ostream &Str) const {
3449 if (!BuildDefs::dump())
3450 return;
3451 Str << "#0.0" << getFpWidthString(Ty);
3452 }
3453
emit(const Cfg * Func) const3454 void OperandARM32FlexReg::emit(const Cfg *Func) const {
3455 if (!BuildDefs::dump())
3456 return;
3457 Ostream &Str = Func->getContext()->getStrEmit();
3458 getReg()->emit(Func);
3459 if (getShiftOp() != kNoShift) {
3460 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " ";
3461 getShiftAmt()->emit(Func);
3462 }
3463 }
3464
dump(const Cfg * Func,Ostream & Str) const3465 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const {
3466 if (!BuildDefs::dump())
3467 return;
3468 Variable *Reg = getReg();
3469 if (Func)
3470 Reg->dump(Func);
3471 else
3472 Reg->dump(Str);
3473 if (getShiftOp() != kNoShift) {
3474 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " ";
3475 if (Func)
3476 getShiftAmt()->dump(Func);
3477 else
3478 getShiftAmt()->dump(Str);
3479 }
3480 }
3481
3482 // Force instantition of template classes
3483 template class InstARM32ThreeAddrGPR<InstARM32::Adc>;
3484 template class InstARM32ThreeAddrGPR<InstARM32::Add>;
3485 template class InstARM32ThreeAddrGPR<InstARM32::And>;
3486 template class InstARM32ThreeAddrGPR<InstARM32::Asr>;
3487 template class InstARM32ThreeAddrGPR<InstARM32::Bic>;
3488 template class InstARM32ThreeAddrGPR<InstARM32::Eor>;
3489 template class InstARM32ThreeAddrGPR<InstARM32::Lsl>;
3490 template class InstARM32ThreeAddrGPR<InstARM32::Lsr>;
3491 template class InstARM32ThreeAddrGPR<InstARM32::Mul>;
3492 template class InstARM32ThreeAddrGPR<InstARM32::Orr>;
3493 template class InstARM32ThreeAddrGPR<InstARM32::Rsb>;
3494 template class InstARM32ThreeAddrGPR<InstARM32::Rsc>;
3495 template class InstARM32ThreeAddrGPR<InstARM32::Sbc>;
3496 template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>;
3497 template class InstARM32ThreeAddrGPR<InstARM32::Sub>;
3498 template class InstARM32ThreeAddrGPR<InstARM32::Udiv>;
3499
3500 template class InstARM32ThreeAddrFP<InstARM32::Vadd>;
3501 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcge>;
3502 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcgt>;
3503 template class InstARM32ThreeAddrFP<InstARM32::Vdiv>;
3504 template class InstARM32ThreeAddrFP<InstARM32::Veor>;
3505 template class InstARM32FourAddrFP<InstARM32::Vmla>;
3506 template class InstARM32FourAddrFP<InstARM32::Vmls>;
3507 template class InstARM32ThreeAddrFP<InstARM32::Vmul>;
3508 template class InstARM32UnaryopSignAwareFP<InstARM32::Vneg>;
3509 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>;
3510 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>;
3511 template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
3512 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqadd>;
3513 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqsub>;
3514 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqmovn2>;
3515 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vmulh>;
3516 template class InstARM32ThreeAddrFP<InstARM32::Vmlap>;
3517
3518 template class InstARM32LoadBase<InstARM32::Ldr>;
3519 template class InstARM32LoadBase<InstARM32::Ldrex>;
3520 template class InstARM32LoadBase<InstARM32::Vldr1d>;
3521 template class InstARM32LoadBase<InstARM32::Vldr1q>;
3522 template class InstARM32ThreeAddrFP<InstARM32::Vzip>;
3523 template class InstARM32TwoAddrGPR<InstARM32::Movt>;
3524
3525 template class InstARM32UnaryopGPR<InstARM32::Movw, false>;
3526 template class InstARM32UnaryopGPR<InstARM32::Clz, false>;
3527 template class InstARM32UnaryopGPR<InstARM32::Mvn, false>;
3528 template class InstARM32UnaryopGPR<InstARM32::Rbit, false>;
3529 template class InstARM32UnaryopGPR<InstARM32::Rev, false>;
3530 template class InstARM32UnaryopGPR<InstARM32::Sxt, true>;
3531 template class InstARM32UnaryopGPR<InstARM32::Uxt, true>;
3532 template class InstARM32UnaryopFP<InstARM32::Vsqrt>;
3533
3534 template class InstARM32FourAddrGPR<InstARM32::Mla>;
3535 template class InstARM32FourAddrGPR<InstARM32::Mls>;
3536
3537 template class InstARM32CmpLike<InstARM32::Cmn>;
3538 template class InstARM32CmpLike<InstARM32::Cmp>;
3539 template class InstARM32CmpLike<InstARM32::Tst>;
3540
3541 } // end of namespace ARM32
3542 } // end of namespace Ice
3543