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