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