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
dump(const Cfg * Func) const1817 void InstARM32::dump(const Cfg *Func) const {
1818 if (!BuildDefs::dump())
1819 return;
1820 Ostream &Str = Func->getContext()->getStrDump();
1821 Str << "[ARM32] ";
1822 Inst::dump(Func);
1823 }
1824
emitMultiDestSingleSource(const Cfg * Func) const1825 void InstARM32Mov::emitMultiDestSingleSource(const Cfg *Func) const {
1826 if (!BuildDefs::dump())
1827 return;
1828 Ostream &Str = Func->getContext()->getStrEmit();
1829 Variable *DestLo = getDest();
1830 Variable *DestHi = getDestHi();
1831 auto *Src = llvm::cast<Variable>(getSrc(0));
1832
1833 assert(DestHi->hasReg());
1834 assert(DestLo->hasReg());
1835 assert(Src->hasReg());
1836
1837 Str << "\t"
1838 "vmov"
1839 << getPredicate() << "\t";
1840 DestLo->emit(Func);
1841 Str << ", ";
1842 DestHi->emit(Func);
1843 Str << ", ";
1844 Src->emit(Func);
1845 }
1846
emitSingleDestMultiSource(const Cfg * Func) const1847 void InstARM32Mov::emitSingleDestMultiSource(const Cfg *Func) const {
1848 if (!BuildDefs::dump())
1849 return;
1850 Ostream &Str = Func->getContext()->getStrEmit();
1851 Variable *Dest = getDest();
1852 auto *SrcLo = llvm::cast<Variable>(getSrc(0));
1853 auto *SrcHi = llvm::cast<Variable>(getSrc(1));
1854
1855 assert(SrcHi->hasReg());
1856 assert(SrcLo->hasReg());
1857 assert(Dest->hasReg());
1858 assert(getSrcSize() == 2);
1859
1860 Str << "\t"
1861 "vmov"
1862 << getPredicate() << "\t";
1863 Dest->emit(Func);
1864 Str << ", ";
1865 SrcLo->emit(Func);
1866 Str << ", ";
1867 SrcHi->emit(Func);
1868 }
1869
1870 namespace {
1871
isVariableWithoutRegister(const Operand * Op)1872 bool isVariableWithoutRegister(const Operand *Op) {
1873 if (const auto *OpV = llvm::dyn_cast<Variable>(Op)) {
1874 return !OpV->hasReg();
1875 }
1876 return false;
1877 }
isMemoryAccess(Operand * Op)1878 bool isMemoryAccess(Operand *Op) {
1879 return isVariableWithoutRegister(Op) || llvm::isa<OperandARM32Mem>(Op);
1880 }
1881
isMoveBetweenCoreAndVFPRegisters(Variable * Dest,Operand * Src)1882 bool isMoveBetweenCoreAndVFPRegisters(Variable *Dest, Operand *Src) {
1883 const Type DestTy = Dest->getType();
1884 const Type SrcTy = Src->getType();
1885 return !isVectorType(DestTy) && !isVectorType(SrcTy) &&
1886 (isScalarIntegerType(DestTy) == isScalarFloatingType(SrcTy));
1887 }
1888
1889 } // end of anonymous namespace
1890
emitSingleDestSingleSource(const Cfg * Func) const1891 void InstARM32Mov::emitSingleDestSingleSource(const Cfg *Func) const {
1892 if (!BuildDefs::dump())
1893 return;
1894 Ostream &Str = Func->getContext()->getStrEmit();
1895 Variable *Dest = getDest();
1896
1897 if (!Dest->hasReg()) {
1898 llvm::report_fatal_error("mov can't store.");
1899 }
1900
1901 Operand *Src0 = getSrc(0);
1902 if (isMemoryAccess(Src0)) {
1903 llvm::report_fatal_error("mov can't load.");
1904 }
1905
1906 Type Ty = Dest->getType();
1907 const bool IsVector = isVectorType(Ty);
1908 const bool IsScalarFP = isScalarFloatingType(Ty);
1909 const bool CoreVFPMove = isMoveBetweenCoreAndVFPRegisters(Dest, Src0);
1910 const bool IsVMove = (IsVector || IsScalarFP || CoreVFPMove);
1911 const char *Opcode = IsVMove ? "vmov" : "mov";
1912 // when vmov{c}'ing, we need to emit a width string. Otherwise, the
1913 // assembler might be tempted to assume we want a vector vmov{c}, and that
1914 // is disallowed because ARM.
1915 const char *WidthString = !CoreVFPMove ? getFpWidthString(Ty) : "";
1916 CondARM32::Cond Cond = getPredicate();
1917 if (IsVector)
1918 assert(CondARM32::isUnconditional(Cond) &&
1919 "Moves on vectors must be unconditional!");
1920 Str << "\t" << Opcode;
1921 if (IsVMove) {
1922 Str << Cond << WidthString;
1923 } else {
1924 Str << WidthString << Cond;
1925 }
1926 Str << "\t";
1927 Dest->emit(Func);
1928 Str << ", ";
1929 Src0->emit(Func);
1930 }
1931
emit(const Cfg * Func) const1932 void InstARM32Mov::emit(const Cfg *Func) const {
1933 if (!BuildDefs::dump())
1934 return;
1935 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
1936 if (isMultiDest()) {
1937 emitMultiDestSingleSource(Func);
1938 return;
1939 }
1940
1941 if (isMultiSource()) {
1942 emitSingleDestMultiSource(Func);
1943 return;
1944 }
1945
1946 emitSingleDestSingleSource(Func);
1947 }
1948
emitIAS(const Cfg * Func) const1949 void InstARM32Mov::emitIAS(const Cfg *Func) const {
1950 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
1951 const Variable *Dest = getDest();
1952 Operand *Src0 = getSrc(0);
1953 const CondARM32::Cond Cond = getPredicate();
1954 if (!Dest->hasReg()) {
1955 llvm::report_fatal_error("mov can't store.");
1956 }
1957 if (isMemoryAccess(Src0)) {
1958 llvm::report_fatal_error("mov can't load.");
1959 }
1960
1961 assert(!(isMultiDest() && isMultiSource()) && "Invalid vmov type.");
1962 if (isMultiDest()) {
1963 Asm->vmovrrd(Dest, getDestHi(), Src0, Cond);
1964 return;
1965 }
1966 if (isMultiSource()) {
1967 Asm->vmovdrr(Dest, Src0, getSrc(1), Cond);
1968 return;
1969 }
1970
1971 const Type DestTy = Dest->getType();
1972 const Type SrcTy = Src0->getType();
1973 switch (DestTy) {
1974 default:
1975 break; // Error
1976 case IceType_i1:
1977 case IceType_i8:
1978 case IceType_i16:
1979 case IceType_i32:
1980 switch (SrcTy) {
1981 default:
1982 break; // Error
1983 case IceType_i1:
1984 case IceType_i8:
1985 case IceType_i16:
1986 case IceType_i32:
1987 case IceType_i64:
1988 Asm->mov(Dest, Src0, Cond);
1989 return;
1990 case IceType_f32:
1991 Asm->vmovrs(Dest, Src0, Cond);
1992 return;
1993 }
1994 break; // Error
1995 case IceType_i64:
1996 if (isScalarIntegerType(SrcTy)) {
1997 Asm->mov(Dest, Src0, Cond);
1998 return;
1999 }
2000 if (SrcTy == IceType_f64) {
2001 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2002 Asm->vmovdd(Dest, Var, Cond);
2003 return;
2004 }
2005 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2006 Asm->vmovd(Dest, FpImm, Cond);
2007 return;
2008 }
2009 }
2010 break; // Error
2011 case IceType_f32:
2012 switch (SrcTy) {
2013 default:
2014 break; // Error
2015 case IceType_i1:
2016 case IceType_i8:
2017 case IceType_i16:
2018 case IceType_i32:
2019 return Asm->vmovsr(Dest, Src0, Cond);
2020 case IceType_f32:
2021 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2022 Asm->vmovss(Dest, Var, Cond);
2023 return;
2024 }
2025 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2026 Asm->vmovs(Dest, FpImm, Cond);
2027 return;
2028 }
2029 break; // Error
2030 }
2031 break; // Error
2032 case IceType_f64:
2033 if (SrcTy == IceType_f64) {
2034 if (const auto *Var = llvm::dyn_cast<Variable>(Src0)) {
2035 Asm->vmovdd(Dest, Var, Cond);
2036 return;
2037 }
2038 if (const auto *FpImm = llvm::dyn_cast<OperandARM32FlexFpImm>(Src0)) {
2039 Asm->vmovd(Dest, FpImm, Cond);
2040 return;
2041 }
2042 }
2043 break; // Error
2044 // TODO(jpp): Remove vectors of i1.
2045 case IceType_v4i1:
2046 case IceType_v8i1:
2047 case IceType_v16i1:
2048 case IceType_v16i8:
2049 case IceType_v8i16:
2050 case IceType_v4i32:
2051 case IceType_v4f32:
2052 assert(CondARM32::isUnconditional(Cond) &&
2053 "Moves on vector must be unconditional!");
2054 if (isVectorType(SrcTy)) {
2055 // Mov between different Src and Dest types is used for bitcasting
2056 // vectors. We still want to make sure SrcTy is a vector type.
2057 Asm->vorrq(Dest, Src0, Src0);
2058 return;
2059 } else if (const auto *C = llvm::dyn_cast<ConstantInteger32>(Src0)) {
2060 // Mov with constant argument, allowing the initializing all elements of
2061 // the vector.
2062 if (Asm->vmovqc(Dest, C))
2063 return;
2064 }
2065 }
2066 llvm::report_fatal_error("Mov: don't know how to move " +
2067 typeStdString(SrcTy) + " to " +
2068 typeStdString(DestTy));
2069 }
2070
dump(const Cfg * Func) const2071 void InstARM32Mov::dump(const Cfg *Func) const {
2072 if (!BuildDefs::dump())
2073 return;
2074 assert(getSrcSize() == 1 || getSrcSize() == 2);
2075 Ostream &Str = Func->getContext()->getStrDump();
2076 Variable *Dest = getDest();
2077 Variable *DestHi = getDestHi();
2078 Dest->dump(Func);
2079 if (DestHi) {
2080 Str << ", ";
2081 DestHi->dump(Func);
2082 }
2083
2084 dumpOpcodePred(Str, " = mov", getDest()->getType());
2085 Str << " ";
2086
2087 dumpSources(Func);
2088 }
2089
emit(const Cfg * Func) const2090 void InstARM32Br::emit(const Cfg *Func) const {
2091 if (!BuildDefs::dump())
2092 return;
2093 Ostream &Str = Func->getContext()->getStrEmit();
2094 Str << "\t"
2095 "b"
2096 << getPredicate() << "\t";
2097 if (Label) {
2098 Str << Label->getLabelName();
2099 } else {
2100 if (isUnconditionalBranch()) {
2101 Str << getTargetFalse()->getAsmName();
2102 } else {
2103 Str << getTargetTrue()->getAsmName();
2104 if (getTargetFalse()) {
2105 startNextInst(Func);
2106 Str << "\n\t"
2107 << "b"
2108 << "\t" << getTargetFalse()->getAsmName();
2109 }
2110 }
2111 }
2112 }
2113
emitIAS(const Cfg * Func) const2114 void InstARM32Br::emitIAS(const Cfg *Func) const {
2115 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2116 if (Label) {
2117 Asm->b(Asm->getOrCreateLocalLabel(Label->getNumber()), getPredicate());
2118 } else if (isUnconditionalBranch()) {
2119 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetFalse()->getIndex()),
2120 getPredicate());
2121 } else {
2122 Asm->b(Asm->getOrCreateCfgNodeLabel(getTargetTrue()->getIndex()),
2123 getPredicate());
2124 if (const CfgNode *False = getTargetFalse())
2125 Asm->b(Asm->getOrCreateCfgNodeLabel(False->getIndex()), CondARM32::AL);
2126 }
2127 if (Asm->needsTextFixup())
2128 emitUsingTextFixup(Func);
2129 }
2130
dump(const Cfg * Func) const2131 void InstARM32Br::dump(const Cfg *Func) const {
2132 if (!BuildDefs::dump())
2133 return;
2134 Ostream &Str = Func->getContext()->getStrDump();
2135 Str << "br ";
2136
2137 if (getPredicate() == CondARM32::AL) {
2138 if (Label) {
2139 Str << "label %" << Label->getLabelName();
2140 } else {
2141 Str << "label %" << getTargetFalse()->getName();
2142 }
2143 return;
2144 }
2145
2146 if (Label) {
2147 Str << getPredicate() << ", label %" << Label->getLabelName();
2148 } else {
2149 Str << getPredicate() << ", label %" << getTargetTrue()->getName();
2150 if (getTargetFalse()) {
2151 Str << ", label %" << getTargetFalse()->getName();
2152 }
2153 }
2154 }
2155
emit(const Cfg * Func) const2156 void InstARM32Call::emit(const Cfg *Func) const {
2157 if (!BuildDefs::dump())
2158 return;
2159 Ostream &Str = Func->getContext()->getStrEmit();
2160 assert(getSrcSize() == 1);
2161 if (llvm::isa<ConstantInteger32>(getCallTarget())) {
2162 // This shouldn't happen (typically have to copy the full 32-bits to a
2163 // register and do an indirect jump).
2164 llvm::report_fatal_error("ARM32Call to ConstantInteger32");
2165 } else if (const auto *CallTarget =
2166 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
2167 // Calls only have 24-bits, but the linker should insert veneers to extend
2168 // the range if needed.
2169 Str << "\t"
2170 "bl"
2171 "\t";
2172 CallTarget->emitWithoutPrefix(Func->getTarget());
2173 } else {
2174 Str << "\t"
2175 "blx"
2176 "\t";
2177 getCallTarget()->emit(Func);
2178 }
2179 }
2180
emitIAS(const Cfg * Func) const2181 void InstARM32Call::emitIAS(const Cfg *Func) const {
2182 assert(getSrcSize() == 1);
2183 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2184 if (llvm::isa<ConstantInteger32>(getCallTarget())) {
2185 // This shouldn't happen (typically have to copy the full 32-bits to a
2186 // register and do an indirect jump).
2187 llvm::report_fatal_error("ARM32Call to ConstantInteger32");
2188 } else if (const auto *CallTarget =
2189 llvm::dyn_cast<ConstantRelocatable>(getCallTarget())) {
2190 // Calls only have 24-bits, but the linker should insert veneers to extend
2191 // the range if needed.
2192 Asm->bl(CallTarget);
2193 } else {
2194 Asm->blx(getCallTarget());
2195 }
2196 if (Asm->needsTextFixup())
2197 return emitUsingTextFixup(Func);
2198 }
2199
dump(const Cfg * Func) const2200 void InstARM32Call::dump(const Cfg *Func) const {
2201 if (!BuildDefs::dump())
2202 return;
2203 Ostream &Str = Func->getContext()->getStrDump();
2204 if (getDest()) {
2205 dumpDest(Func);
2206 Str << " = ";
2207 }
2208 Str << "call ";
2209 getCallTarget()->dump(Func);
2210 }
2211
emit(const Cfg * Func) const2212 void InstARM32Label::emit(const Cfg *Func) const {
2213 if (!BuildDefs::dump())
2214 return;
2215 // A label is not really an instruction. Hence, we need to fix the
2216 // emitted text size.
2217 if (auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>())
2218 Asm->decEmitTextSize(InstSize);
2219 Ostream &Str = Func->getContext()->getStrEmit();
2220 Str << getLabelName() << ":";
2221 }
2222
emitIAS(const Cfg * Func) const2223 void InstARM32Label::emitIAS(const Cfg *Func) const {
2224 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2225 Asm->bindLocalLabel(this, Number);
2226 if (OffsetReloc != nullptr) {
2227 Asm->bindRelocOffset(OffsetReloc);
2228 }
2229 if (Asm->needsTextFixup())
2230 emitUsingTextFixup(Func);
2231 }
2232
dump(const Cfg * Func) const2233 void InstARM32Label::dump(const Cfg *Func) const {
2234 if (!BuildDefs::dump())
2235 return;
2236 Ostream &Str = Func->getContext()->getStrDump();
2237 Str << getLabelName() << ":";
2238 }
2239
2240 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2241 void InstARM32LoadBase<K>::emitIAS(const Cfg *Func) const {
2242 emitUsingTextFixup(Func);
2243 }
2244
emit(const Cfg * Func) const2245 template <> void InstARM32Ldr::emit(const Cfg *Func) const {
2246 if (!BuildDefs::dump())
2247 return;
2248 Ostream &Str = Func->getContext()->getStrEmit();
2249 assert(getSrcSize() == 1);
2250 assert(getDest()->hasReg());
2251 Variable *Dest = getDest();
2252 Type Ty = Dest->getType();
2253 const bool IsVector = isVectorType(Ty);
2254 const bool IsScalarFloat = isScalarFloatingType(Ty);
2255 const char *ActualOpcode =
2256 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2257 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2258 Str << "\t" << ActualOpcode;
2259 const bool IsVInst = IsVector || IsScalarFloat;
2260 if (IsVInst) {
2261 Str << getPredicate() << WidthString;
2262 } else {
2263 Str << WidthString << getPredicate();
2264 }
2265 if (IsVector)
2266 Str << "." << getVecElmtBitsize(Ty);
2267 Str << "\t";
2268 getDest()->emit(Func);
2269 Str << ", ";
2270 getSrc(0)->emit(Func);
2271 }
2272
emit(const Cfg * Func) const2273 template <> void InstARM32Vldr1d::emit(const Cfg *Func) const {
2274 if (!BuildDefs::dump())
2275 return;
2276 Ostream &Str = Func->getContext()->getStrEmit();
2277 assert(getSrcSize() == 1);
2278 assert(getDest()->hasReg());
2279 Variable *Dest = getDest();
2280 Type Ty = Dest->getType();
2281 const bool IsVector = isVectorType(Ty);
2282 const bool IsScalarFloat = isScalarFloatingType(Ty);
2283 const char *ActualOpcode =
2284 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2285 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2286 Str << "\t" << ActualOpcode;
2287 const bool IsVInst = IsVector || IsScalarFloat;
2288 if (IsVInst) {
2289 Str << getPredicate() << WidthString;
2290 } else {
2291 Str << WidthString << getPredicate();
2292 }
2293 if (IsVector)
2294 Str << "." << getVecElmtBitsize(Ty);
2295 Str << "\t";
2296 getDest()->emit(Func);
2297 Str << ", ";
2298 getSrc(0)->emit(Func);
2299 }
2300
emit(const Cfg * Func) const2301 template <> void InstARM32Vldr1q::emit(const Cfg *Func) const {
2302 if (!BuildDefs::dump())
2303 return;
2304 Ostream &Str = Func->getContext()->getStrEmit();
2305 assert(getSrcSize() == 1);
2306 assert(getDest()->hasReg());
2307 Variable *Dest = getDest();
2308 Type Ty = Dest->getType();
2309 const bool IsVector = isVectorType(Ty);
2310 const bool IsScalarFloat = isScalarFloatingType(Ty);
2311 const char *ActualOpcode =
2312 IsVector ? "vld1" : (IsScalarFloat ? "vldr" : "ldr");
2313 const char *WidthString = IsVector ? "" : getWidthString(Ty);
2314 Str << "\t" << ActualOpcode;
2315 const bool IsVInst = IsVector || IsScalarFloat;
2316 if (IsVInst) {
2317 Str << getPredicate() << WidthString;
2318 } else {
2319 Str << WidthString << getPredicate();
2320 }
2321 if (IsVector)
2322 Str << "." << getVecElmtBitsize(Ty);
2323 Str << "\t";
2324 getDest()->emit(Func);
2325 Str << ", ";
2326 getSrc(0)->emit(Func);
2327 }
2328
emitIAS(const Cfg * Func) const2329 template <> void InstARM32Ldr::emitIAS(const Cfg *Func) const {
2330 assert(getSrcSize() == 1);
2331 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2332 Variable *Dest = getDest();
2333 const Type DestTy = Dest->getType();
2334 switch (DestTy) {
2335 default:
2336 llvm::report_fatal_error("Ldr on unknown type: " + typeStdString(DestTy));
2337 case IceType_i1:
2338 case IceType_i8:
2339 case IceType_i16:
2340 case IceType_i32:
2341 case IceType_i64:
2342 Asm->ldr(Dest, getSrc(0), getPredicate(), Func->getTarget());
2343 break;
2344 case IceType_f32:
2345 Asm->vldrs(Dest, getSrc(0), getPredicate(), Func->getTarget());
2346 break;
2347 case IceType_f64:
2348 Asm->vldrd(Dest, getSrc(0), getPredicate(), Func->getTarget());
2349 break;
2350 case IceType_v16i8:
2351 case IceType_v8i16:
2352 case IceType_v4i32:
2353 case IceType_v4f32:
2354 case IceType_v16i1:
2355 case IceType_v8i1:
2356 case IceType_v4i1:
2357 Asm->vld1qr(getVecElmtBitsize(DestTy), Dest, getSrc(0), Func->getTarget());
2358 break;
2359 }
2360 }
2361
emitIAS(const Cfg * Func) const2362 template <> void InstARM32Vldr1d::emitIAS(const Cfg *Func) const {
2363 assert(getSrcSize() == 1);
2364 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2365 Variable *Dest = getDest();
2366 Asm->vld1(32, Dest, getSrc(0), Func->getTarget());
2367 }
2368
emitIAS(const Cfg * Func) const2369 template <> void InstARM32Vldr1q::emitIAS(const Cfg *Func) const {
2370 assert(getSrcSize() == 1);
2371 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2372 Variable *Dest = getDest();
2373 Asm->vld1(64, Dest, getSrc(0), Func->getTarget());
2374 }
2375
emit(const Cfg * Func) const2376 template <> void InstARM32Ldrex::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 DestTy = Dest->getType();
2384 assert(isScalarIntegerType(DestTy));
2385 const char *WidthString = getWidthString(DestTy);
2386 Str << "\t" << Opcode << WidthString << getPredicate() << "\t";
2387 getDest()->emit(Func);
2388 Str << ", ";
2389 getSrc(0)->emit(Func);
2390 }
2391
emitIAS(const Cfg * Func) const2392 template <> void InstARM32Ldrex::emitIAS(const Cfg *Func) const {
2393 assert(getSrcSize() == 1);
2394 assert(getDest()->hasReg());
2395 Variable *Dest = getDest();
2396 assert(isScalarIntegerType(Dest->getType()));
2397 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2398 Asm->ldrex(Dest, getSrc(0), getPredicate(), Func->getTarget());
2399 if (Asm->needsTextFixup())
2400 emitUsingTextFixup(Func);
2401 }
2402
2403 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2404 void InstARM32TwoAddrGPR<K>::emitIAS(const Cfg *Func) const {
2405 emitUsingTextFixup(Func);
2406 }
2407
2408 template <InstARM32::InstKindARM32 K, bool Nws>
emitIAS(const Cfg * Func) const2409 void InstARM32UnaryopGPR<K, Nws>::emitIAS(const Cfg *Func) const {
2410 emitUsingTextFixup(Func);
2411 }
2412
emitIAS(const Cfg * Func) const2413 template <> void InstARM32Rbit::emitIAS(const Cfg *Func) const {
2414 assert(getSrcSize() == 1);
2415 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2416 Asm->rbit(getDest(), getSrc(0), getPredicate());
2417 if (Asm->needsTextFixup())
2418 emitUsingTextFixup(Func);
2419 }
2420
emitIAS(const Cfg * Func) const2421 template <> void InstARM32Rev::emitIAS(const Cfg *Func) const {
2422 assert(getSrcSize() == 1);
2423 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2424 Asm->rev(getDest(), getSrc(0), getPredicate());
2425 if (Asm->needsTextFixup())
2426 emitUsingTextFixup(Func);
2427 }
2428
emit(const Cfg * Func) const2429 template <> void InstARM32Movw::emit(const Cfg *Func) const {
2430 if (!BuildDefs::dump())
2431 return;
2432 Ostream &Str = Func->getContext()->getStrEmit();
2433 assert(getSrcSize() == 1);
2434 Str << "\t" << Opcode << getPredicate() << "\t";
2435 getDest()->emit(Func);
2436 Str << ", ";
2437 auto *Src0 = llvm::cast<Constant>(getSrc(0));
2438 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src0)) {
2439 Str << "#:lower16:";
2440 CR->emitWithoutPrefix(Func->getTarget());
2441 } else {
2442 Src0->emit(Func);
2443 }
2444 }
2445
emitIAS(const Cfg * Func) const2446 template <> void InstARM32Movw::emitIAS(const Cfg *Func) const {
2447 assert(getSrcSize() == 1);
2448 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2449 Asm->movw(getDest(), getSrc(0), getPredicate());
2450 if (Asm->needsTextFixup())
2451 emitUsingTextFixup(Func);
2452 }
2453
emit(const Cfg * Func) const2454 template <> void InstARM32Movt::emit(const Cfg *Func) const {
2455 if (!BuildDefs::dump())
2456 return;
2457 Ostream &Str = Func->getContext()->getStrEmit();
2458 assert(getSrcSize() == 2);
2459 Variable *Dest = getDest();
2460 auto *Src1 = llvm::cast<Constant>(getSrc(1));
2461 Str << "\t" << Opcode << getPredicate() << "\t";
2462 Dest->emit(Func);
2463 Str << ", ";
2464 if (auto *CR = llvm::dyn_cast<ConstantRelocatable>(Src1)) {
2465 Str << "#:upper16:";
2466 CR->emitWithoutPrefix(Func->getTarget());
2467 } else {
2468 Src1->emit(Func);
2469 }
2470 }
2471
emitIAS(const Cfg * Func) const2472 template <> void InstARM32Movt::emitIAS(const Cfg *Func) const {
2473 assert(getSrcSize() == 2);
2474 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2475 Asm->movt(getDest(), getSrc(1), getPredicate());
2476 if (Asm->needsTextFixup())
2477 emitUsingTextFixup(Func);
2478 }
2479
emitIAS(const Cfg * Func) const2480 template <> void InstARM32Clz::emitIAS(const Cfg *Func) const {
2481 assert(getSrcSize() == 1);
2482 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2483 Asm->clz(getDest(), getSrc(0), getPredicate());
2484 if (Asm->needsTextFixup())
2485 emitUsingTextFixup(Func);
2486 }
2487
emitIAS(const Cfg * Func) const2488 template <> void InstARM32Mvn::emitIAS(const Cfg *Func) const {
2489 assert(getSrcSize() == 1);
2490 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2491 Asm->mvn(getDest(), getSrc(0), getPredicate());
2492 if (Asm->needsTextFixup())
2493 emitUsingTextFixup(Func);
2494 }
2495
emitIAS(const Cfg * Func) const2496 template <> void InstARM32Sxt::emitIAS(const Cfg *Func) const {
2497 assert(getSrcSize() == 1);
2498 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2499 Asm->sxt(getDest(), getSrc(0), getPredicate());
2500 if (Asm->needsTextFixup())
2501 emitUsingTextFixup(Func);
2502 }
2503
emitIAS(const Cfg * Func) const2504 template <> void InstARM32Uxt::emitIAS(const Cfg *Func) const {
2505 assert(getSrcSize() == 1);
2506 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2507 Asm->uxt(getDest(), getSrc(0), getPredicate());
2508 if (Asm->needsTextFixup())
2509 emitUsingTextFixup(Func);
2510 }
2511
2512 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2513 void InstARM32UnaryopFP<K>::emitIAS(const Cfg *Func) const {
2514 emitUsingTextFixup(Func);
2515 }
2516
2517 template <InstARM32::InstKindARM32 K>
emitIAS(const Cfg * Func) const2518 void InstARM32UnaryopSignAwareFP<K>::emitIAS(const Cfg *Func) const {
2519 InstARM32::emitUsingTextFixup(Func);
2520 }
2521
emitIAS(const Cfg * Func) const2522 template <> void InstARM32Vsqrt::emitIAS(const Cfg *Func) const {
2523 assert(getSrcSize() == 1);
2524 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2525 const Operand *Dest = getDest();
2526 switch (Dest->getType()) {
2527 case IceType_f32:
2528 Asm->vsqrts(Dest, getSrc(0), getPredicate());
2529 break;
2530 case IceType_f64:
2531 Asm->vsqrtd(Dest, getSrc(0), getPredicate());
2532 break;
2533 default:
2534 llvm::report_fatal_error("Vsqrt of non-floating type");
2535 }
2536 if (Asm->needsTextFixup())
2537 emitUsingTextFixup(Func);
2538 }
2539
getGPROpcode() const2540 const char *InstARM32Pop::getGPROpcode() const { return "pop"; }
2541
getSRegOpcode() const2542 const char *InstARM32Pop::getSRegOpcode() const { return "vpop"; }
2543
getStackReg(SizeT Index) const2544 Variable *InstARM32Pop::getStackReg(SizeT Index) const { return Dests[Index]; }
2545
getNumStackRegs() const2546 SizeT InstARM32Pop::getNumStackRegs() const { return Dests.size(); }
2547
emitSingleGPR(const Cfg * Func,const EmitForm Form,const Variable * Reg) const2548 void InstARM32Pop::emitSingleGPR(const Cfg *Func, const EmitForm Form,
2549 const Variable *Reg) const {
2550 switch (Form) {
2551 case Emit_Text:
2552 emitGPRsAsText(Func);
2553 return;
2554 case Emit_Binary:
2555 Func->getAssembler<ARM32::AssemblerARM32>()->pop(Reg, CondARM32::AL);
2556 return;
2557 }
2558 }
2559
emitMultipleGPRs(const Cfg * Func,const EmitForm Form,IValueT Registers) const2560 void InstARM32Pop::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
2561 IValueT Registers) const {
2562 switch (Form) {
2563 case Emit_Text:
2564 emitGPRsAsText(Func);
2565 return;
2566 case Emit_Binary:
2567 Func->getAssembler<ARM32::AssemblerARM32>()->popList(Registers,
2568 CondARM32::AL);
2569 return;
2570 }
2571 }
2572
emitSRegs(const Cfg * Func,const EmitForm Form,const Variable * BaseReg,SizeT RegCount) const2573 void InstARM32Pop::emitSRegs(const Cfg *Func, const EmitForm Form,
2574 const Variable *BaseReg, SizeT RegCount) const {
2575 switch (Form) {
2576 case Emit_Text:
2577 emitSRegsAsText(Func, BaseReg, RegCount);
2578 return;
2579 case Emit_Binary:
2580 Func->getAssembler<ARM32::AssemblerARM32>()->vpop(BaseReg, RegCount,
2581 CondARM32::AL);
2582 return;
2583 }
2584 }
2585
getGPROpcode() const2586 const char *InstARM32Push::getGPROpcode() const { return "push"; }
2587
getSRegOpcode() const2588 const char *InstARM32Push::getSRegOpcode() const { return "vpush"; }
2589
getStackReg(SizeT Index) const2590 Variable *InstARM32Push::getStackReg(SizeT Index) const {
2591 return llvm::cast<Variable>(getSrc(Index));
2592 }
2593
getNumStackRegs() const2594 SizeT InstARM32Push::getNumStackRegs() const { return getSrcSize(); }
2595
emitSingleGPR(const Cfg * Func,const EmitForm Form,const Variable * Reg) const2596 void InstARM32Push::emitSingleGPR(const Cfg *Func, const EmitForm Form,
2597 const Variable *Reg) const {
2598 switch (Form) {
2599 case Emit_Text:
2600 emitGPRsAsText(Func);
2601 return;
2602 case Emit_Binary:
2603 Func->getAssembler<ARM32::AssemblerARM32>()->push(Reg, CondARM32::AL);
2604 return;
2605 }
2606 }
2607
emitMultipleGPRs(const Cfg * Func,const EmitForm Form,IValueT Registers) const2608 void InstARM32Push::emitMultipleGPRs(const Cfg *Func, const EmitForm Form,
2609 IValueT Registers) const {
2610 switch (Form) {
2611 case Emit_Text:
2612 emitGPRsAsText(Func);
2613 return;
2614 case Emit_Binary:
2615 Func->getAssembler<ARM32::AssemblerARM32>()->pushList(Registers,
2616 CondARM32::AL);
2617 return;
2618 }
2619 }
2620
emitSRegs(const Cfg * Func,const EmitForm Form,const Variable * BaseReg,SizeT RegCount) const2621 void InstARM32Push::emitSRegs(const Cfg *Func, const EmitForm Form,
2622 const Variable *BaseReg, SizeT RegCount) const {
2623 switch (Form) {
2624 case Emit_Text:
2625 emitSRegsAsText(Func, BaseReg, RegCount);
2626 return;
2627 case Emit_Binary:
2628 Func->getAssembler<ARM32::AssemblerARM32>()->vpush(BaseReg, RegCount,
2629 CondARM32::AL);
2630 return;
2631 }
2632 }
2633
emit(const Cfg * Func) const2634 void InstARM32Ret::emit(const Cfg *Func) const {
2635 if (!BuildDefs::dump())
2636 return;
2637 assert(getSrcSize() > 0);
2638 auto *LR = llvm::cast<Variable>(getSrc(0));
2639 assert(LR->hasReg());
2640 assert(LR->getRegNum() == RegARM32::Reg_lr);
2641 Ostream &Str = Func->getContext()->getStrEmit();
2642 Str << "\t"
2643 "bx"
2644 "\t";
2645 LR->emit(Func);
2646 }
2647
emitIAS(const Cfg * Func) const2648 void InstARM32Ret::emitIAS(const Cfg *Func) const {
2649 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2650 Asm->bx(RegARM32::Encoded_Reg_lr);
2651 if (Asm->needsTextFixup())
2652 emitUsingTextFixup(Func);
2653 }
2654
dump(const Cfg * Func) const2655 void InstARM32Ret::dump(const Cfg *Func) const {
2656 if (!BuildDefs::dump())
2657 return;
2658 Ostream &Str = Func->getContext()->getStrDump();
2659 Type Ty = (getSrcSize() == 1 ? IceType_void : getSrc(0)->getType());
2660 Str << "ret." << Ty << " ";
2661 dumpSources(Func);
2662 }
2663
emit(const Cfg * Func) const2664 void InstARM32Str::emit(const Cfg *Func) const {
2665 if (!BuildDefs::dump())
2666 return;
2667 Ostream &Str = Func->getContext()->getStrEmit();
2668 assert(getSrcSize() == 2);
2669 Type Ty = getSrc(0)->getType();
2670 const bool IsVectorStore = isVectorType(Ty);
2671 const bool IsScalarFloat = isScalarFloatingType(Ty);
2672 const char *Opcode =
2673 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str");
2674 Str << "\t" << Opcode;
2675 const bool IsVInst = IsVectorStore || IsScalarFloat;
2676 if (IsVInst) {
2677 Str << getPredicate() << getWidthString(Ty);
2678 } else {
2679 Str << getWidthString(Ty) << getPredicate();
2680 }
2681 if (IsVectorStore)
2682 Str << "." << getVecElmtBitsize(Ty);
2683 Str << "\t";
2684 getSrc(0)->emit(Func);
2685 Str << ", ";
2686 getSrc(1)->emit(Func);
2687 }
2688
emitIAS(const Cfg * Func) const2689 void InstARM32Str::emitIAS(const Cfg *Func) const {
2690 assert(getSrcSize() == 2);
2691 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2692 const Operand *Src0 = getSrc(0);
2693 const Operand *Src1 = getSrc(1);
2694 Type Ty = Src0->getType();
2695 switch (Ty) {
2696 default:
2697 llvm::report_fatal_error("Str on unknown type: " + typeStdString(Ty));
2698 case IceType_i1:
2699 case IceType_i8:
2700 case IceType_i16:
2701 case IceType_i32:
2702 case IceType_i64:
2703 Asm->str(Src0, Src1, getPredicate(), Func->getTarget());
2704 break;
2705 case IceType_f32:
2706 Asm->vstrs(Src0, Src1, getPredicate(), Func->getTarget());
2707 break;
2708 case IceType_f64:
2709 Asm->vstrd(Src0, Src1, getPredicate(), Func->getTarget());
2710 break;
2711 case IceType_v16i8:
2712 case IceType_v8i16:
2713 case IceType_v4i32:
2714 case IceType_v4f32:
2715 case IceType_v16i1:
2716 case IceType_v8i1:
2717 case IceType_v4i1:
2718 Asm->vst1qr(getVecElmtBitsize(Ty), Src0, Src1, Func->getTarget());
2719 break;
2720 }
2721 }
2722
dump(const Cfg * Func) const2723 void InstARM32Str::dump(const Cfg *Func) const {
2724 if (!BuildDefs::dump())
2725 return;
2726 Ostream &Str = Func->getContext()->getStrDump();
2727 Type Ty = getSrc(0)->getType();
2728 dumpOpcodePred(Str, "str", Ty);
2729 Str << " ";
2730 getSrc(1)->dump(Func);
2731 Str << ", ";
2732 getSrc(0)->dump(Func);
2733 }
2734
emit(const Cfg * Func) const2735 void InstARM32Strex::emit(const Cfg *Func) const {
2736 if (!BuildDefs::dump())
2737 return;
2738 assert(getSrcSize() == 2);
2739 Type Ty = getSrc(0)->getType();
2740 assert(isScalarIntegerType(Ty));
2741 Variable *Dest = getDest();
2742 Ostream &Str = Func->getContext()->getStrEmit();
2743 static constexpr char Opcode[] = "strex";
2744 const char *WidthString = getWidthString(Ty);
2745 Str << "\t" << Opcode << WidthString << getPredicate() << "\t";
2746 Dest->emit(Func);
2747 Str << ", ";
2748 emitSources(Func);
2749 }
2750
emitIAS(const Cfg * Func) const2751 void InstARM32Strex::emitIAS(const Cfg *Func) const {
2752 assert(getSrcSize() == 2);
2753 const Operand *Src0 = getSrc(0);
2754 assert(isScalarIntegerType(Src0->getType()));
2755 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2756 Asm->strex(Dest, Src0, getSrc(1), getPredicate(), Func->getTarget());
2757 if (Asm->needsTextFixup())
2758 emitUsingTextFixup(Func);
2759 }
2760
dump(const Cfg * Func) const2761 void InstARM32Strex::dump(const Cfg *Func) const {
2762 if (!BuildDefs::dump())
2763 return;
2764 Ostream &Str = Func->getContext()->getStrDump();
2765 Variable *Dest = getDest();
2766 Dest->dump(Func);
2767 Str << " = ";
2768 Type Ty = getSrc(0)->getType();
2769 dumpOpcodePred(Str, "strex", Ty);
2770 Str << " ";
2771 getSrc(1)->dump(Func);
2772 Str << ", ";
2773 getSrc(0)->dump(Func);
2774 }
2775
emit(const Cfg * Func) const2776 void InstARM32Vstr1::emit(const Cfg *Func) const {
2777 if (!BuildDefs::dump())
2778 return;
2779 Ostream &Str = Func->getContext()->getStrEmit();
2780 assert(getSrcSize() == 2);
2781 Type Ty = getSrc(0)->getType();
2782 const bool IsVectorStore = isVectorType(Ty);
2783 const bool IsScalarFloat = isScalarFloatingType(Ty);
2784 const char *Opcode =
2785 IsVectorStore ? "vst1" : (IsScalarFloat ? "vstr" : "str");
2786 Str << "\t" << Opcode;
2787 const bool IsVInst = IsVectorStore || IsScalarFloat;
2788 if (IsVInst) {
2789 Str << getPredicate() << getWidthString(Ty);
2790 } else {
2791 Str << getWidthString(Ty) << getPredicate();
2792 }
2793 if (IsVectorStore)
2794 Str << "." << getVecElmtBitsize(Ty);
2795 Str << "\t";
2796 getSrc(0)->emit(Func);
2797 Str << ", ";
2798 getSrc(1)->emit(Func);
2799 }
2800
emitIAS(const Cfg * Func) const2801 void InstARM32Vstr1::emitIAS(const Cfg *Func) const {
2802 assert(getSrcSize() == 2);
2803 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2804 const Operand *Src0 = getSrc(0);
2805 const Operand *Src1 = getSrc(1);
2806 Asm->vst1(Size, Src0, Src1, Func->getTarget());
2807 }
2808
dump(const Cfg * Func) const2809 void InstARM32Vstr1::dump(const Cfg *Func) const {
2810 if (!BuildDefs::dump())
2811 return;
2812 Ostream &Str = Func->getContext()->getStrDump();
2813 Type Ty = getSrc(0)->getType();
2814 dumpOpcodePred(Str, "str", Ty);
2815 Str << " ";
2816 getSrc(1)->dump(Func);
2817 Str << ", ";
2818 getSrc(0)->dump(Func);
2819 }
2820
emit(const Cfg * Func) const2821 void InstARM32Vdup::emit(const Cfg *Func) const {
2822 if (!BuildDefs::dump())
2823 return;
2824 Ostream &Str = Func->getContext()->getStrEmit();
2825 assert(getSrcSize() == 2);
2826 Type Ty = getSrc(0)->getType();
2827 const char *Opcode = "vdup";
2828 Str << "\t" << Opcode;
2829 Str << getPredicate() << "." << getWidthString(Ty) << getVecElmtBitsize(Ty);
2830 Str << "\t";
2831 getSrc(0)->emit(Func);
2832 Str << ", ";
2833 getSrc(1)->emit(Func);
2834 Str << ", " << Idx;
2835 }
2836
emitIAS(const Cfg * Func) const2837 void InstARM32Vdup::emitIAS(const Cfg *Func) const {
2838 assert(getSrcSize() == 1);
2839 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2840 const Operand *Dest = getDest();
2841 const Operand *Src = getSrc(0);
2842 Type DestTy = Dest->getType();
2843 Asm->vdup(typeElementType(DestTy), Dest, Src, Idx);
2844 }
2845
dump(const Cfg * Func) const2846 void InstARM32Vdup::dump(const Cfg *Func) const {
2847 if (!BuildDefs::dump())
2848 return;
2849 Ostream &Str = Func->getContext()->getStrDump();
2850 dumpDest(Func);
2851 Str << " = ";
2852 dumpOpcodePred(Str, "vdup", getDest()->getType());
2853 Str << " ";
2854 dumpSources(Func);
2855 Str << ", " << Idx;
2856 }
2857
emit(const Cfg * Func) const2858 void InstARM32Trap::emit(const Cfg *Func) const {
2859 if (!BuildDefs::dump())
2860 return;
2861 Ostream &Str = Func->getContext()->getStrEmit();
2862 assert(getSrcSize() == 0);
2863 // There isn't a mnemonic for the special NaCl Trap encoding, so dump
2864 // the raw bytes.
2865 Str << "\t.long 0x";
2866 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2867 for (uint8_t I : Asm->getNonExecBundlePadding()) {
2868 Str.write_hex(I);
2869 }
2870 }
2871
emitIAS(const Cfg * Func) const2872 void InstARM32Trap::emitIAS(const Cfg *Func) const {
2873 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2874 Asm->trap();
2875 assert(!Asm->needsTextFixup());
2876 }
2877
dump(const Cfg * Func) const2878 void InstARM32Trap::dump(const Cfg *Func) const {
2879 if (!BuildDefs::dump())
2880 return;
2881 Ostream &Str = Func->getContext()->getStrDump();
2882 Str << "trap";
2883 }
2884
emit(const Cfg * Func) const2885 void InstARM32Umull::emit(const Cfg *Func) const {
2886 if (!BuildDefs::dump())
2887 return;
2888 Ostream &Str = Func->getContext()->getStrEmit();
2889 assert(getSrcSize() == 2);
2890 assert(getDest()->hasReg());
2891 Str << "\t"
2892 "umull"
2893 << getPredicate() << "\t";
2894 getDest()->emit(Func);
2895 Str << ", ";
2896 DestHi->emit(Func);
2897 Str << ", ";
2898 getSrc(0)->emit(Func);
2899 Str << ", ";
2900 getSrc(1)->emit(Func);
2901 }
2902
emitIAS(const Cfg * Func) const2903 void InstARM32Umull::emitIAS(const Cfg *Func) const {
2904 assert(getSrcSize() == 2);
2905 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2906 Asm->umull(getDest(), DestHi, getSrc(0), getSrc(1), getPredicate());
2907 if (Asm->needsTextFixup())
2908 emitUsingTextFixup(Func);
2909 }
2910
dump(const Cfg * Func) const2911 void InstARM32Umull::dump(const Cfg *Func) const {
2912 if (!BuildDefs::dump())
2913 return;
2914 Ostream &Str = Func->getContext()->getStrDump();
2915 dumpDest(Func);
2916 Str << " = ";
2917 dumpOpcodePred(Str, "umull", getDest()->getType());
2918 Str << " ";
2919 dumpSources(Func);
2920 }
2921
2922 namespace {
vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant)2923 const char *vcvtVariantSuffix(const InstARM32Vcvt::VcvtVariant Variant) {
2924 switch (Variant) {
2925 case InstARM32Vcvt::S2si:
2926 return ".s32.f32";
2927 case InstARM32Vcvt::S2ui:
2928 return ".u32.f32";
2929 case InstARM32Vcvt::Si2s:
2930 return ".f32.s32";
2931 case InstARM32Vcvt::Ui2s:
2932 return ".f32.u32";
2933 case InstARM32Vcvt::D2si:
2934 return ".s32.f64";
2935 case InstARM32Vcvt::D2ui:
2936 return ".u32.f64";
2937 case InstARM32Vcvt::Si2d:
2938 return ".f64.s32";
2939 case InstARM32Vcvt::Ui2d:
2940 return ".f64.u32";
2941 case InstARM32Vcvt::S2d:
2942 return ".f64.f32";
2943 case InstARM32Vcvt::D2s:
2944 return ".f32.f64";
2945 case InstARM32Vcvt::Vs2si:
2946 return ".s32.f32";
2947 case InstARM32Vcvt::Vs2ui:
2948 return ".u32.f32";
2949 case InstARM32Vcvt::Vsi2s:
2950 return ".f32.s32";
2951 case InstARM32Vcvt::Vui2s:
2952 return ".f32.u32";
2953 }
2954 llvm::report_fatal_error("Invalid VcvtVariant enum.");
2955 }
2956 } // end of anonymous namespace
2957
emit(const Cfg * Func) const2958 void InstARM32Vcvt::emit(const Cfg *Func) const {
2959 if (!BuildDefs::dump())
2960 return;
2961 Ostream &Str = Func->getContext()->getStrEmit();
2962 assert(getSrcSize() == 1);
2963 assert(getDest()->hasReg());
2964 Str << "\t"
2965 "vcvt"
2966 << getPredicate() << vcvtVariantSuffix(Variant) << "\t";
2967 getDest()->emit(Func);
2968 Str << ", ";
2969 getSrc(0)->emit(Func);
2970 }
2971
emitIAS(const Cfg * Func) const2972 void InstARM32Vcvt::emitIAS(const Cfg *Func) const {
2973 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
2974 switch (Variant) {
2975 case S2si:
2976 Asm->vcvtis(getDest(), getSrc(0), getPredicate());
2977 break;
2978 case S2ui:
2979 Asm->vcvtus(getDest(), getSrc(0), getPredicate());
2980 break;
2981 case Si2s:
2982 Asm->vcvtsi(getDest(), getSrc(0), getPredicate());
2983 break;
2984 case Ui2s:
2985 Asm->vcvtsu(getDest(), getSrc(0), getPredicate());
2986 break;
2987 case D2si:
2988 Asm->vcvtid(getDest(), getSrc(0), getPredicate());
2989 break;
2990 case D2ui:
2991 Asm->vcvtud(getDest(), getSrc(0), getPredicate());
2992 break;
2993 case Si2d:
2994 Asm->vcvtdi(getDest(), getSrc(0), getPredicate());
2995 break;
2996 case Ui2d:
2997 Asm->vcvtdu(getDest(), getSrc(0), getPredicate());
2998 break;
2999 case S2d:
3000 Asm->vcvtds(getDest(), getSrc(0), getPredicate());
3001 break;
3002 case D2s:
3003 Asm->vcvtsd(getDest(), getSrc(0), getPredicate());
3004 break;
3005 case Vs2si:
3006 Asm->vcvtqsi(getDest(), getSrc(0));
3007 break;
3008 case Vs2ui:
3009 Asm->vcvtqsu(getDest(), getSrc(0));
3010 break;
3011 case Vsi2s:
3012 Asm->vcvtqis(getDest(), getSrc(0));
3013 break;
3014 case Vui2s:
3015 Asm->vcvtqus(getDest(), getSrc(0));
3016 break;
3017 }
3018 assert(!Asm->needsTextFixup());
3019 }
3020
dump(const Cfg * Func) const3021 void InstARM32Vcvt::dump(const Cfg *Func) const {
3022 if (!BuildDefs::dump())
3023 return;
3024 Ostream &Str = Func->getContext()->getStrDump();
3025 dumpDest(Func);
3026 Str << " = "
3027 << "vcvt" << getPredicate() << vcvtVariantSuffix(Variant) << " ";
3028 dumpSources(Func);
3029 }
3030
emit(const Cfg * Func) const3031 void InstARM32Vcmp::emit(const Cfg *Func) const {
3032 if (!BuildDefs::dump())
3033 return;
3034 Ostream &Str = Func->getContext()->getStrEmit();
3035 assert(getSrcSize() == 2);
3036 Str << "\t"
3037 "vcmp"
3038 << getPredicate() << getFpWidthString(getSrc(0)->getType()) << "\t";
3039 getSrc(0)->emit(Func);
3040 Str << ", ";
3041 getSrc(1)->emit(Func);
3042 }
3043
emitIAS(const Cfg * Func) const3044 void InstARM32Vcmp::emitIAS(const Cfg *Func) const {
3045 assert(getSrcSize() == 2);
3046 const Operand *Src0 = getSrc(0);
3047 const Type Ty = Src0->getType();
3048 const Operand *Src1 = getSrc(1);
3049 const CondARM32::Cond Cond = getPredicate();
3050 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3051 if (llvm::isa<OperandARM32FlexFpZero>(Src1)) {
3052 switch (Ty) {
3053 case IceType_f32:
3054 Asm->vcmpsz(Src0, Cond);
3055 break;
3056 case IceType_f64:
3057 Asm->vcmpdz(Src0, Cond);
3058 break;
3059 default:
3060 llvm::report_fatal_error("Vcvt on non floating value");
3061 }
3062 } else {
3063 switch (Ty) {
3064 case IceType_f32:
3065 Asm->vcmps(Src0, Src1, Cond);
3066 break;
3067 case IceType_f64:
3068 Asm->vcmpd(Src0, Src1, Cond);
3069 break;
3070 default:
3071 llvm::report_fatal_error("Vcvt on non floating value");
3072 }
3073 }
3074 assert(!Asm->needsTextFixup());
3075 }
3076
dump(const Cfg * Func) const3077 void InstARM32Vcmp::dump(const Cfg *Func) const {
3078 if (!BuildDefs::dump())
3079 return;
3080 Ostream &Str = Func->getContext()->getStrDump();
3081 Str << "vcmp" << getPredicate() << getFpWidthString(getSrc(0)->getType());
3082 dumpSources(Func);
3083 }
3084
emit(const Cfg * Func) const3085 void InstARM32Vmrs::emit(const Cfg *Func) const {
3086 if (!BuildDefs::dump())
3087 return;
3088 Ostream &Str = Func->getContext()->getStrEmit();
3089 assert(getSrcSize() == 0);
3090 Str << "\t"
3091 "vmrs"
3092 << getPredicate()
3093 << "\t"
3094 "APSR_nzcv"
3095 ", "
3096 "FPSCR";
3097 }
3098
emitIAS(const Cfg * Func) const3099 void InstARM32Vmrs::emitIAS(const Cfg *Func) const {
3100 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3101 Asm->vmrsAPSR_nzcv(getPredicate());
3102 assert(!Asm->needsTextFixup());
3103 }
3104
dump(const Cfg * Func) const3105 void InstARM32Vmrs::dump(const Cfg *Func) const {
3106 if (!BuildDefs::dump())
3107 return;
3108 Ostream &Str = Func->getContext()->getStrDump();
3109 Str << "APSR{n,z,v,c} = vmrs" << getPredicate()
3110 << "\t"
3111 "FPSCR{n,z,c,v}";
3112 }
3113
emit(const Cfg * Func) const3114 void InstARM32Vabs::emit(const Cfg *Func) const {
3115 if (!BuildDefs::dump())
3116 return;
3117 Ostream &Str = Func->getContext()->getStrEmit();
3118 assert(getSrcSize() == 1);
3119 Str << "\t"
3120 "vabs"
3121 << getPredicate() << getFpWidthString(getSrc(0)->getType()) << "\t";
3122 getDest()->emit(Func);
3123 Str << ", ";
3124 getSrc(0)->emit(Func);
3125 }
3126
emitIAS(const Cfg * Func) const3127 void InstARM32Vabs::emitIAS(const Cfg *Func) const {
3128 assert(getSrcSize() == 1);
3129 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3130 const Variable *Dest = getDest();
3131 switch (Dest->getType()) {
3132 default:
3133 llvm::report_fatal_error("fabs not defined on type " +
3134 typeStdString(Dest->getType()));
3135 case IceType_f32:
3136 Asm->vabss(Dest, getSrc(0), getPredicate());
3137 break;
3138 case IceType_f64:
3139 Asm->vabsd(Dest, getSrc(0), getPredicate());
3140 break;
3141 case IceType_v4f32:
3142 assert(CondARM32::isUnconditional(getPredicate()) &&
3143 "fabs must be unconditional");
3144 Asm->vabsq(Dest, getSrc(0));
3145 }
3146 assert(!Asm->needsTextFixup());
3147 }
3148
dump(const Cfg * Func) const3149 void InstARM32Vabs::dump(const Cfg *Func) const {
3150 if (!BuildDefs::dump())
3151 return;
3152 Ostream &Str = Func->getContext()->getStrDump();
3153 dumpDest(Func);
3154 Str << " = vabs" << getPredicate() << getFpWidthString(getSrc(0)->getType());
3155 }
3156
emit(const Cfg * Func) const3157 void InstARM32Dmb::emit(const Cfg *Func) const {
3158 if (!BuildDefs::dump())
3159 return;
3160 Ostream &Str = Func->getContext()->getStrEmit();
3161 assert(getSrcSize() == 0);
3162 Str << "\t"
3163 "dmb"
3164 "\t"
3165 "sy";
3166 }
3167
emitIAS(const Cfg * Func) const3168 void InstARM32Dmb::emitIAS(const Cfg *Func) const {
3169 assert(getSrcSize() == 0);
3170 auto *Asm = Func->getAssembler<ARM32::AssemblerARM32>();
3171 constexpr ARM32::IValueT SyOption = 0xF; // i.e. 1111
3172 Asm->dmb(SyOption);
3173 if (Asm->needsTextFixup())
3174 emitUsingTextFixup(Func);
3175 }
3176
dump(const Cfg * Func) const3177 void InstARM32Dmb::dump(const Cfg *Func) const {
3178 if (!BuildDefs::dump())
3179 return;
3180 Func->getContext()->getStrDump() << "dmb\t"
3181 "sy";
3182 }
3183
emit(const Cfg * Func) const3184 void InstARM32Nop::emit(const Cfg *Func) const {
3185 if (!BuildDefs::dump())
3186 return;
3187 assert(getSrcSize() == 0);
3188 Func->getContext()->getStrEmit() << "\t"
3189 << "nop";
3190 }
3191
emitIAS(const Cfg * Func) const3192 void InstARM32Nop::emitIAS(const Cfg *Func) const {
3193 assert(getSrcSize() == 0);
3194 Func->getAssembler<ARM32::AssemblerARM32>()->nop();
3195 }
3196
dump(const Cfg * Func) const3197 void InstARM32Nop::dump(const Cfg *Func) const {
3198 if (!BuildDefs::dump())
3199 return;
3200 assert(getSrcSize() == 0);
3201 Func->getContext()->getStrDump() << "nop";
3202 }
3203
emit(const Cfg * Func) const3204 void OperandARM32Mem::emit(const Cfg *Func) const {
3205 if (!BuildDefs::dump())
3206 return;
3207 Ostream &Str = Func->getContext()->getStrEmit();
3208 Str << "[";
3209 getBase()->emit(Func);
3210 switch (getAddrMode()) {
3211 case PostIndex:
3212 case NegPostIndex:
3213 Str << "]";
3214 break;
3215 default:
3216 break;
3217 }
3218 if (isRegReg()) {
3219 Str << ", ";
3220 if (isNegAddrMode()) {
3221 Str << "-";
3222 }
3223 getIndex()->emit(Func);
3224 if (getShiftOp() != kNoShift) {
3225 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #"
3226 << getShiftAmt();
3227 }
3228 } else {
3229 ConstantInteger32 *Offset = getOffset();
3230 if (Offset && Offset->getValue() != 0) {
3231 Str << ", ";
3232 Offset->emit(Func);
3233 }
3234 }
3235 switch (getAddrMode()) {
3236 case Offset:
3237 case NegOffset:
3238 Str << "]";
3239 break;
3240 case PreIndex:
3241 case NegPreIndex:
3242 Str << "]!";
3243 break;
3244 case PostIndex:
3245 case NegPostIndex:
3246 // Brace is already closed off.
3247 break;
3248 }
3249 }
3250
dump(const Cfg * Func,Ostream & Str) const3251 void OperandARM32Mem::dump(const Cfg *Func, Ostream &Str) const {
3252 if (!BuildDefs::dump())
3253 return;
3254 Str << "[";
3255 if (Func)
3256 getBase()->dump(Func);
3257 else
3258 getBase()->dump(Str);
3259 Str << ", ";
3260 if (isRegReg()) {
3261 if (isNegAddrMode()) {
3262 Str << "-";
3263 }
3264 if (Func)
3265 getIndex()->dump(Func);
3266 else
3267 getIndex()->dump(Str);
3268 if (getShiftOp() != kNoShift) {
3269 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " #"
3270 << getShiftAmt();
3271 }
3272 } else {
3273 getOffset()->dump(Func, Str);
3274 }
3275 Str << "] AddrMode==" << getAddrMode();
3276 }
3277
emit(const Cfg * Func) const3278 void OperandARM32ShAmtImm::emit(const Cfg *Func) const { ShAmt->emit(Func); }
3279
dump(const Cfg *,Ostream & Str) const3280 void OperandARM32ShAmtImm::dump(const Cfg *, Ostream &Str) const {
3281 ShAmt->dump(Str);
3282 }
3283
create(Cfg * Func,Type Ty,uint32_t Imm,uint32_t RotateAmt)3284 OperandARM32FlexImm *OperandARM32FlexImm::create(Cfg *Func, Type Ty,
3285 uint32_t Imm,
3286 uint32_t RotateAmt) {
3287 // The assembler wants the smallest rotation. Rotate if needed. Note: Imm is
3288 // an 8-bit value.
3289 assert(Utils::IsUint(8, Imm) &&
3290 "Flex immediates can only be defined on 8-bit immediates");
3291 while ((Imm & 0x03) == 0 && RotateAmt > 0) {
3292 --RotateAmt;
3293 Imm = Imm >> 2;
3294 }
3295 return new (Func->allocate<OperandARM32FlexImm>())
3296 OperandARM32FlexImm(Func, Ty, Imm, RotateAmt);
3297 }
3298
emit(const Cfg * Func) const3299 void OperandARM32FlexImm::emit(const Cfg *Func) const {
3300 if (!BuildDefs::dump())
3301 return;
3302 Ostream &Str = Func->getContext()->getStrEmit();
3303 uint32_t Imm = getImm();
3304 uint32_t RotateAmt = getRotateAmt();
3305 Str << "#" << Utils::rotateRight32(Imm, 2 * RotateAmt);
3306 }
3307
dump(const Cfg *,Ostream & Str) const3308 void OperandARM32FlexImm::dump(const Cfg * /* Func */, Ostream &Str) const {
3309 if (!BuildDefs::dump())
3310 return;
3311 uint32_t Imm = getImm();
3312 uint32_t RotateAmt = getRotateAmt();
3313 Str << "#(" << Imm << " ror 2*" << RotateAmt << ")";
3314 }
3315
3316 namespace {
3317 static constexpr uint32_t a = 0x80;
3318 static constexpr uint32_t b = 0x40;
3319 static constexpr uint32_t cdefgh = 0x3F;
3320 static constexpr uint32_t AllowedBits = a | b | cdefgh;
3321 static_assert(AllowedBits == 0xFF,
3322 "Invalid mask for f32/f64 constant rematerialization.");
3323
3324 // There's no loss in always returning the modified immediate as float.
3325 // TODO(jpp): returning a double causes problems when outputting the constants
3326 // for filetype=asm. Why?
materializeFloatImmediate(uint32_t ModifiedImm)3327 float materializeFloatImmediate(uint32_t ModifiedImm) {
3328 const uint32_t Ret = ((ModifiedImm & a) ? 0x80000000 : 0) |
3329 ((ModifiedImm & b) ? 0x3E000000 : 0x40000000) |
3330 ((ModifiedImm & cdefgh) << 19);
3331 return Utils::bitCopy<float>(Ret);
3332 }
3333
3334 } // end of anonymous namespace
3335
emit(const Cfg * Func) const3336 void OperandARM32FlexFpImm::emit(const Cfg *Func) const {
3337 if (!BuildDefs::dump())
3338 return;
3339 Ostream &Str = Func->getContext()->getStrEmit();
3340 switch (Ty) {
3341 default:
3342 llvm::report_fatal_error("Invalid flex fp imm type.");
3343 case IceType_f64:
3344 case IceType_f32:
3345 Str << "#" << materializeFloatImmediate(ModifiedImm)
3346 << " @ Modified: " << ModifiedImm;
3347 break;
3348 }
3349 }
3350
dump(const Cfg *,Ostream & Str) const3351 void OperandARM32FlexFpImm::dump(const Cfg * /*Func*/, Ostream &Str) const {
3352 if (!BuildDefs::dump())
3353 return;
3354 Str << "#" << materializeFloatImmediate(ModifiedImm) << getFpWidthString(Ty);
3355 }
3356
emit(const Cfg * Func) const3357 void OperandARM32FlexFpZero::emit(const Cfg *Func) const {
3358 if (!BuildDefs::dump())
3359 return;
3360 Ostream &Str = Func->getContext()->getStrEmit();
3361 switch (Ty) {
3362 default:
3363 llvm::report_fatal_error("Invalid flex fp imm type.");
3364 case IceType_f64:
3365 case IceType_f32:
3366 Str << "#0.0";
3367 }
3368 }
3369
dump(const Cfg *,Ostream & Str) const3370 void OperandARM32FlexFpZero::dump(const Cfg * /*Func*/, Ostream &Str) const {
3371 if (!BuildDefs::dump())
3372 return;
3373 Str << "#0.0" << getFpWidthString(Ty);
3374 }
3375
emit(const Cfg * Func) const3376 void OperandARM32FlexReg::emit(const Cfg *Func) const {
3377 if (!BuildDefs::dump())
3378 return;
3379 Ostream &Str = Func->getContext()->getStrEmit();
3380 getReg()->emit(Func);
3381 if (getShiftOp() != kNoShift) {
3382 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " ";
3383 getShiftAmt()->emit(Func);
3384 }
3385 }
3386
dump(const Cfg * Func,Ostream & Str) const3387 void OperandARM32FlexReg::dump(const Cfg *Func, Ostream &Str) const {
3388 if (!BuildDefs::dump())
3389 return;
3390 Variable *Reg = getReg();
3391 if (Func)
3392 Reg->dump(Func);
3393 else
3394 Reg->dump(Str);
3395 if (getShiftOp() != kNoShift) {
3396 Str << ", " << InstARM32ShiftAttributes[getShiftOp()].EmitString << " ";
3397 if (Func)
3398 getShiftAmt()->dump(Func);
3399 else
3400 getShiftAmt()->dump(Str);
3401 }
3402 }
3403
3404 // Force instantition of template classes
3405 template class InstARM32ThreeAddrGPR<InstARM32::Adc>;
3406 template class InstARM32ThreeAddrGPR<InstARM32::Add>;
3407 template class InstARM32ThreeAddrGPR<InstARM32::And>;
3408 template class InstARM32ThreeAddrGPR<InstARM32::Asr>;
3409 template class InstARM32ThreeAddrGPR<InstARM32::Bic>;
3410 template class InstARM32ThreeAddrGPR<InstARM32::Eor>;
3411 template class InstARM32ThreeAddrGPR<InstARM32::Lsl>;
3412 template class InstARM32ThreeAddrGPR<InstARM32::Lsr>;
3413 template class InstARM32ThreeAddrGPR<InstARM32::Mul>;
3414 template class InstARM32ThreeAddrGPR<InstARM32::Orr>;
3415 template class InstARM32ThreeAddrGPR<InstARM32::Rsb>;
3416 template class InstARM32ThreeAddrGPR<InstARM32::Rsc>;
3417 template class InstARM32ThreeAddrGPR<InstARM32::Sbc>;
3418 template class InstARM32ThreeAddrGPR<InstARM32::Sdiv>;
3419 template class InstARM32ThreeAddrGPR<InstARM32::Sub>;
3420 template class InstARM32ThreeAddrGPR<InstARM32::Udiv>;
3421
3422 template class InstARM32ThreeAddrFP<InstARM32::Vadd>;
3423 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcge>;
3424 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vcgt>;
3425 template class InstARM32ThreeAddrFP<InstARM32::Vdiv>;
3426 template class InstARM32ThreeAddrFP<InstARM32::Veor>;
3427 template class InstARM32FourAddrFP<InstARM32::Vmla>;
3428 template class InstARM32FourAddrFP<InstARM32::Vmls>;
3429 template class InstARM32ThreeAddrFP<InstARM32::Vmul>;
3430 template class InstARM32UnaryopSignAwareFP<InstARM32::Vneg>;
3431 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshl>;
3432 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vshr>;
3433 template class InstARM32ThreeAddrFP<InstARM32::Vsub>;
3434 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqadd>;
3435 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqsub>;
3436 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vqmovn2>;
3437 template class InstARM32ThreeAddrSignAwareFP<InstARM32::Vmulh>;
3438 template class InstARM32ThreeAddrFP<InstARM32::Vmlap>;
3439
3440 template class InstARM32LoadBase<InstARM32::Ldr>;
3441 template class InstARM32LoadBase<InstARM32::Ldrex>;
3442 template class InstARM32LoadBase<InstARM32::Vldr1d>;
3443 template class InstARM32LoadBase<InstARM32::Vldr1q>;
3444 template class InstARM32ThreeAddrFP<InstARM32::Vzip>;
3445 template class InstARM32TwoAddrGPR<InstARM32::Movt>;
3446
3447 template class InstARM32UnaryopGPR<InstARM32::Movw, false>;
3448 template class InstARM32UnaryopGPR<InstARM32::Clz, false>;
3449 template class InstARM32UnaryopGPR<InstARM32::Mvn, false>;
3450 template class InstARM32UnaryopGPR<InstARM32::Rbit, false>;
3451 template class InstARM32UnaryopGPR<InstARM32::Rev, false>;
3452 template class InstARM32UnaryopGPR<InstARM32::Sxt, true>;
3453 template class InstARM32UnaryopGPR<InstARM32::Uxt, true>;
3454 template class InstARM32UnaryopFP<InstARM32::Vsqrt>;
3455
3456 template class InstARM32FourAddrGPR<InstARM32::Mla>;
3457 template class InstARM32FourAddrGPR<InstARM32::Mls>;
3458
3459 template class InstARM32CmpLike<InstARM32::Cmn>;
3460 template class InstARM32CmpLike<InstARM32::Cmp>;
3461 template class InstARM32CmpLike<InstARM32::Tst>;
3462
3463 } // end of namespace ARM32
3464 } // end of namespace Ice
3465