OLD | NEW |
1 //===- subzero/src/IceTargetLoweringARM32.h - ARM32 lowering ----*- C++ -*-===// | 1 //===- subzero/src/IceTargetLoweringARM32.h - ARM32 lowering ----*- C++ -*-===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
182 CondARM32::Cond); | 182 CondARM32::Cond); |
183 void lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, Operand *Src1, | 183 void lowerIDivRem(Variable *Dest, Variable *T, Variable *Src0R, Operand *Src1, |
184 ExtInstr ExtFunc, DivInstr DivFunc, | 184 ExtInstr ExtFunc, DivInstr DivFunc, |
185 const char *DivHelperName, bool IsRemainder); | 185 const char *DivHelperName, bool IsRemainder); |
186 | 186 |
187 void lowerCLZ(Variable *Dest, Variable *ValLo, Variable *ValHi); | 187 void lowerCLZ(Variable *Dest, Variable *ValLo, Variable *ValHi); |
188 | 188 |
189 // The following are helpers that insert lowered ARM32 instructions with | 189 // The following are helpers that insert lowered ARM32 instructions with |
190 // minimal syntactic overhead, so that the lowering code can look as close to | 190 // minimal syntactic overhead, so that the lowering code can look as close to |
191 // assembly as practical. | 191 // assembly as practical. |
192 | |
193 void _add(Variable *Dest, Variable *Src0, Operand *Src1, | 192 void _add(Variable *Dest, Variable *Src0, Operand *Src1, |
194 CondARM32::Cond Pred = CondARM32::AL) { | 193 CondARM32::Cond Pred = CondARM32::AL) { |
195 Context.insert(InstARM32Add::create(Func, Dest, Src0, Src1, Pred)); | 194 Context.insert(InstARM32Add::create(Func, Dest, Src0, Src1, Pred)); |
196 } | 195 } |
197 void _adds(Variable *Dest, Variable *Src0, Operand *Src1, | 196 void _adds(Variable *Dest, Variable *Src0, Operand *Src1, |
198 CondARM32::Cond Pred = CondARM32::AL) { | 197 CondARM32::Cond Pred = CondARM32::AL) { |
199 constexpr bool SetFlags = true; | 198 constexpr bool SetFlags = true; |
200 Context.insert( | 199 Context.insert( |
201 InstARM32Add::create(Func, Dest, Src0, Src1, Pred, SetFlags)); | 200 InstARM32Add::create(Func, Dest, Src0, Src1, Pred, SetFlags)); |
202 } | 201 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 Context.insert(InstARM32Cmp::create(Func, Src0, Src1, Pred)); | 238 Context.insert(InstARM32Cmp::create(Func, Src0, Src1, Pred)); |
240 } | 239 } |
241 void _clz(Variable *Dest, Variable *Src0, | 240 void _clz(Variable *Dest, Variable *Src0, |
242 CondARM32::Cond Pred = CondARM32::AL) { | 241 CondARM32::Cond Pred = CondARM32::AL) { |
243 Context.insert(InstARM32Clz::create(Func, Dest, Src0, Pred)); | 242 Context.insert(InstARM32Clz::create(Func, Dest, Src0, Pred)); |
244 } | 243 } |
245 void _eor(Variable *Dest, Variable *Src0, Operand *Src1, | 244 void _eor(Variable *Dest, Variable *Src0, Operand *Src1, |
246 CondARM32::Cond Pred = CondARM32::AL) { | 245 CondARM32::Cond Pred = CondARM32::AL) { |
247 Context.insert(InstARM32Eor::create(Func, Dest, Src0, Src1, Pred)); | 246 Context.insert(InstARM32Eor::create(Func, Dest, Src0, Src1, Pred)); |
248 } | 247 } |
| 248 /// _ldr, for all your memory to Variable data moves. It handles all types |
| 249 /// (integer, floating point, and vectors.) Addr needs to be valid for Dest's |
| 250 /// type (e.g., no immediates for vector loads, and no index registers for fp |
| 251 /// loads.) |
249 void _ldr(Variable *Dest, OperandARM32Mem *Addr, | 252 void _ldr(Variable *Dest, OperandARM32Mem *Addr, |
250 CondARM32::Cond Pred = CondARM32::AL) { | 253 CondARM32::Cond Pred = CondARM32::AL) { |
251 Context.insert(InstARM32Ldr::create(Func, Dest, Addr, Pred)); | 254 Context.insert(InstARM32Ldr::create(Func, Dest, Addr, Pred)); |
252 } | 255 } |
253 void _lsl(Variable *Dest, Variable *Src0, Operand *Src1, | 256 void _lsl(Variable *Dest, Variable *Src0, Operand *Src1, |
254 CondARM32::Cond Pred = CondARM32::AL) { | 257 CondARM32::Cond Pred = CondARM32::AL) { |
255 Context.insert(InstARM32Lsl::create(Func, Dest, Src0, Src1, Pred)); | 258 Context.insert(InstARM32Lsl::create(Func, Dest, Src0, Src1, Pred)); |
256 } | 259 } |
257 void _lsr(Variable *Dest, Variable *Src0, Operand *Src1, | 260 void _lsr(Variable *Dest, Variable *Src0, Operand *Src1, |
258 CondARM32::Cond Pred = CondARM32::AL) { | 261 CondARM32::Cond Pred = CondARM32::AL) { |
259 Context.insert(InstARM32Lsr::create(Func, Dest, Src0, Src1, Pred)); | 262 Context.insert(InstARM32Lsr::create(Func, Dest, Src0, Src1, Pred)); |
260 } | 263 } |
261 void _mla(Variable *Dest, Variable *Src0, Variable *Src1, Variable *Acc, | 264 void _mla(Variable *Dest, Variable *Src0, Variable *Src1, Variable *Acc, |
262 CondARM32::Cond Pred = CondARM32::AL) { | 265 CondARM32::Cond Pred = CondARM32::AL) { |
263 Context.insert(InstARM32Mla::create(Func, Dest, Src0, Src1, Acc, Pred)); | 266 Context.insert(InstARM32Mla::create(Func, Dest, Src0, Src1, Acc, Pred)); |
264 } | 267 } |
265 void _mls(Variable *Dest, Variable *Src0, Variable *Src1, Variable *Acc, | 268 void _mls(Variable *Dest, Variable *Src0, Variable *Src1, Variable *Acc, |
266 CondARM32::Cond Pred = CondARM32::AL) { | 269 CondARM32::Cond Pred = CondARM32::AL) { |
267 Context.insert(InstARM32Mls::create(Func, Dest, Src0, Src1, Acc, Pred)); | 270 Context.insert(InstARM32Mls::create(Func, Dest, Src0, Src1, Acc, Pred)); |
268 } | 271 } |
269 /// If Dest=nullptr is passed in, then a new variable is created, marked as | 272 /// _mov, for all your Variable to Variable data movement needs. It handles |
270 /// infinite register allocation weight, and returned through the in/out Dest | 273 /// all types (integer, floating point, and vectors), as well as moves between |
271 /// argument. | 274 /// Core and VFP registers. This is not a panacea: you must obey the (weird, |
272 void _mov(Variable *&Dest, Operand *Src0, | 275 /// confusing, non-uniform) rules for data moves in ARM. |
273 CondARM32::Cond Pred = CondARM32::AL, | 276 void _mov(Variable *Dest, Operand *Src0, |
274 int32_t RegNum = Variable::NoRegister) { | 277 CondARM32::Cond Pred = CondARM32::AL) { |
275 if (Dest == nullptr) | 278 // _mov used to be unique in the sense that it would create a temporary |
276 Dest = makeReg(Src0->getType(), RegNum); | 279 // automagically if Dest was nullptr. It won't do that anymore, so we keep |
| 280 // an assert around just in case there is some untested code path where Dest |
| 281 // is nullptr. |
| 282 assert(Dest != nullptr); |
277 Context.insert(InstARM32Mov::create(Func, Dest, Src0, Pred)); | 283 Context.insert(InstARM32Mov::create(Func, Dest, Src0, Pred)); |
278 } | 284 } |
279 void _mov_nonkillable(Variable *Dest, Operand *Src0, | 285 void _mov_nonkillable(Variable *Dest, Operand *Src0, |
280 CondARM32::Cond Pred = CondARM32::AL) { | 286 CondARM32::Cond Pred = CondARM32::AL) { |
281 Inst *NewInst = InstARM32Mov::create(Func, Dest, Src0, Pred); | 287 Inst *NewInst = InstARM32Mov::create(Func, Dest, Src0, Pred); |
282 NewInst->setDestNonKillable(); | 288 NewInst->setDestNonKillable(); |
283 Context.insert(NewInst); | 289 Context.insert(NewInst); |
284 } | 290 } |
285 /// The Operand can only be a 16-bit immediate or a ConstantRelocatable (with | 291 /// The Operand can only be a 16-bit immediate or a ConstantRelocatable (with |
286 /// an upper16 relocation). | 292 /// an upper16 relocation). |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
341 void _sbcs(Variable *Dest, Variable *Src0, Operand *Src1, | 347 void _sbcs(Variable *Dest, Variable *Src0, Operand *Src1, |
342 CondARM32::Cond Pred = CondARM32::AL) { | 348 CondARM32::Cond Pred = CondARM32::AL) { |
343 constexpr bool SetFlags = true; | 349 constexpr bool SetFlags = true; |
344 Context.insert( | 350 Context.insert( |
345 InstARM32Sbc::create(Func, Dest, Src0, Src1, Pred, SetFlags)); | 351 InstARM32Sbc::create(Func, Dest, Src0, Src1, Pred, SetFlags)); |
346 } | 352 } |
347 void _sdiv(Variable *Dest, Variable *Src0, Variable *Src1, | 353 void _sdiv(Variable *Dest, Variable *Src0, Variable *Src1, |
348 CondARM32::Cond Pred = CondARM32::AL) { | 354 CondARM32::Cond Pred = CondARM32::AL) { |
349 Context.insert(InstARM32Sdiv::create(Func, Dest, Src0, Src1, Pred)); | 355 Context.insert(InstARM32Sdiv::create(Func, Dest, Src0, Src1, Pred)); |
350 } | 356 } |
| 357 /// _str, for all your Variable to memory transfers. Addr has the same |
| 358 /// restrictions that it does in _ldr. |
351 void _str(Variable *Value, OperandARM32Mem *Addr, | 359 void _str(Variable *Value, OperandARM32Mem *Addr, |
352 CondARM32::Cond Pred = CondARM32::AL) { | 360 CondARM32::Cond Pred = CondARM32::AL) { |
353 Context.insert(InstARM32Str::create(Func, Value, Addr, Pred)); | 361 Context.insert(InstARM32Str::create(Func, Value, Addr, Pred)); |
354 } | 362 } |
355 void _sub(Variable *Dest, Variable *Src0, Operand *Src1, | 363 void _sub(Variable *Dest, Variable *Src0, Operand *Src1, |
356 CondARM32::Cond Pred = CondARM32::AL) { | 364 CondARM32::Cond Pred = CondARM32::AL) { |
357 Context.insert(InstARM32Sub::create(Func, Dest, Src0, Src1, Pred)); | 365 Context.insert(InstARM32Sub::create(Func, Dest, Src0, Src1, Pred)); |
358 } | 366 } |
359 void _subs(Variable *Dest, Variable *Src0, Operand *Src1, | 367 void _subs(Variable *Dest, Variable *Src0, Operand *Src1, |
360 CondARM32::Cond Pred = CondARM32::AL) { | 368 CondARM32::Cond Pred = CondARM32::AL) { |
(...skipping 19 matching lines...) Expand all Loading... |
380 Context.insert( | 388 Context.insert( |
381 InstARM32Umull::create(Func, DestLo, DestHi, Src0, Src1, Pred)); | 389 InstARM32Umull::create(Func, DestLo, DestHi, Src0, Src1, Pred)); |
382 // Model the modification to the second dest as a fake def. Note that the | 390 // Model the modification to the second dest as a fake def. Note that the |
383 // def is not predicated. | 391 // def is not predicated. |
384 Context.insert(InstFakeDef::create(Func, DestHi, DestLo)); | 392 Context.insert(InstFakeDef::create(Func, DestHi, DestLo)); |
385 } | 393 } |
386 void _uxt(Variable *Dest, Variable *Src0, | 394 void _uxt(Variable *Dest, Variable *Src0, |
387 CondARM32::Cond Pred = CondARM32::AL) { | 395 CondARM32::Cond Pred = CondARM32::AL) { |
388 Context.insert(InstARM32Uxt::create(Func, Dest, Src0, Pred)); | 396 Context.insert(InstARM32Uxt::create(Func, Dest, Src0, Pred)); |
389 } | 397 } |
| 398 void _vabs(Variable *Dest, Variable *Src, |
| 399 CondARM32::Cond Pred = CondARM32::AL) { |
| 400 Context.insert(InstARM32Vabs::create(Func, Dest, Src, Pred)); |
| 401 } |
390 void _vadd(Variable *Dest, Variable *Src0, Variable *Src1) { | 402 void _vadd(Variable *Dest, Variable *Src0, Variable *Src1) { |
391 Context.insert(InstARM32Vadd::create(Func, Dest, Src0, Src1)); | 403 Context.insert(InstARM32Vadd::create(Func, Dest, Src0, Src1)); |
392 } | 404 } |
393 void _vcvt(Variable *Dest, Variable *Src, InstARM32Vcvt::VcvtVariant Variant, | 405 void _vcvt(Variable *Dest, Variable *Src, InstARM32Vcvt::VcvtVariant Variant, |
394 CondARM32::Cond Pred = CondARM32::AL) { | 406 CondARM32::Cond Pred = CondARM32::AL) { |
395 Context.insert(InstARM32Vcvt::create(Func, Dest, Src, Variant, Pred)); | 407 Context.insert(InstARM32Vcvt::create(Func, Dest, Src, Variant, Pred)); |
396 } | 408 } |
397 void _vdiv(Variable *Dest, Variable *Src0, Variable *Src1) { | 409 void _vdiv(Variable *Dest, Variable *Src0, Variable *Src1) { |
398 Context.insert(InstARM32Vdiv::create(Func, Dest, Src0, Src1)); | 410 Context.insert(InstARM32Vdiv::create(Func, Dest, Src0, Src1)); |
399 } | 411 } |
400 void _vldr(Variable *Dest, OperandARM32Mem *Src, | |
401 CondARM32::Cond Pred = CondARM32::AL) { | |
402 Context.insert(InstARM32Vldr::create(Func, Dest, Src, Pred)); | |
403 } | |
404 void _vcmp(Variable *Src0, Variable *Src1, | 412 void _vcmp(Variable *Src0, Variable *Src1, |
405 CondARM32::Cond Pred = CondARM32::AL) { | 413 CondARM32::Cond Pred = CondARM32::AL) { |
406 Context.insert(InstARM32Vcmp::create(Func, Src0, Src1, Pred)); | 414 Context.insert(InstARM32Vcmp::create(Func, Src0, Src1, Pred)); |
407 } | 415 } |
408 void _vmrs(CondARM32::Cond Pred = CondARM32::AL) { | 416 void _vmrs(CondARM32::Cond Pred = CondARM32::AL) { |
409 Context.insert(InstARM32Vmrs::create(Func, Pred)); | 417 Context.insert(InstARM32Vmrs::create(Func, Pred)); |
410 } | 418 } |
411 // There are a whole bunch of vmov variants, to transfer within S/D/Q | |
412 // registers, between core integer registers and S/D, and from small | |
413 // immediates into S/D. For integer -> S/D/Q there is a variant which takes | |
414 // two integer register to fill a D, or to fill two consecutive S registers. | |
415 // Vmov can also be used to insert-element. E.g., | |
416 // "vmov.8 d0[1], r0" | |
417 // but insert-element is a "two-address" operation where only part of the | |
418 // register is modified. This cannot model that. | |
419 // | |
420 // This represents the simple single source, single dest variants only. | |
421 void _vmov(Variable *Dest, Operand *Src0, | |
422 CondARM32::Cond Pred = CondARM32::AL) { | |
423 Context.insert(InstARM32Vmov::create(Func, Dest, Src0, Pred)); | |
424 } | |
425 // This represents the single source, multi dest variant. | |
426 void _vmov(InstARM32Vmov::RegisterPair Dests, Variable *Src0) { | |
427 constexpr CondARM32::Cond Pred = CondARM32::AL; | |
428 Context.insert(InstARM32Vmov::create(Func, Dests, Src0, Pred)); | |
429 // The Vmov instruction created above does not define Dests._1. Therefore | |
430 // we add a Dest._1 = FakeDef pseudo instruction. | |
431 Context.insert(InstFakeDef::create(Func, Dests._1)); | |
432 } | |
433 // This represents the multi source, single dest variant. | |
434 void _vmov(Variable *Dest, InstARM32Vmov::RegisterPair Srcs) { | |
435 constexpr CondARM32::Cond Pred = CondARM32::AL; | |
436 Context.insert(InstARM32Vmov::create(Func, Dest, Srcs, Pred)); | |
437 } | |
438 void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) { | 419 void _vmul(Variable *Dest, Variable *Src0, Variable *Src1) { |
439 Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1)); | 420 Context.insert(InstARM32Vmul::create(Func, Dest, Src0, Src1)); |
440 } | 421 } |
441 void _vsqrt(Variable *Dest, Variable *Src, | 422 void _vsqrt(Variable *Dest, Variable *Src, |
442 CondARM32::Cond Pred = CondARM32::AL) { | 423 CondARM32::Cond Pred = CondARM32::AL) { |
443 Context.insert(InstARM32Vsqrt::create(Func, Dest, Src, Pred)); | 424 Context.insert(InstARM32Vsqrt::create(Func, Dest, Src, Pred)); |
444 } | 425 } |
445 void _vsub(Variable *Dest, Variable *Src0, Variable *Src1) { | 426 void _vsub(Variable *Dest, Variable *Src0, Variable *Src1) { |
446 Context.insert(InstARM32Vsub::create(Func, Dest, Src0, Src1)); | 427 Context.insert(InstARM32Vsub::create(Func, Dest, Src0, Src1)); |
447 } | 428 } |
448 | 429 |
449 /// Run a pass through stack variables and ensure that the offsets are legal. | 430 /// Run a pass through stack variables and ensure that the offsets are legal. |
450 /// If the offset is not legal, use a new base register that accounts for the | 431 /// If the offset is not legal, use a new base register that accounts for the |
451 /// offset, such that the addressing mode offset bits are now legal. | 432 /// offset, such that the addressing mode offset bits are now legal. |
452 void legalizeStackSlots(); | 433 void legalizeStackSlots(); |
453 /// Returns true if the given Offset can be represented in a stack ldr/str. | 434 /// Returns true if the given Offset can be represented in a stack ldr/str. |
454 bool isLegalVariableStackOffset(int32_t Offset) const; | 435 bool isLegalVariableStackOffset(Type Ty, int32_t Offset) const; |
455 /// Assuming Var needs its offset legalized, define a new base register | 436 /// Assuming Var needs its offset legalized, define a new base register |
456 /// centered on the given Var's offset and use it. | 437 /// centered on the given Var's offset plus StackAdjust, and use it. |
457 StackVariable *legalizeVariableSlot(Variable *Var, Variable *OrigBaseReg); | 438 StackVariable *legalizeVariableSlot(Variable *Var, int32_t StackAdjust, |
| 439 Variable *OrigBaseReg); |
458 | 440 |
459 TargetARM32Features CPUFeatures; | 441 TargetARM32Features CPUFeatures; |
460 bool UsesFramePointer = false; | 442 bool UsesFramePointer = false; |
461 bool NeedsStackAlignment = false; | 443 bool NeedsStackAlignment = false; |
462 bool MaybeLeafFunc = true; | 444 bool MaybeLeafFunc = true; |
463 size_t SpillAreaSizeBytes = 0; | 445 size_t SpillAreaSizeBytes = 0; |
464 // TODO(jpp): std::array instead of array. | 446 // TODO(jpp): std::array instead of array. |
465 llvm::SmallBitVector TypeToRegisterSet[IceType_NUM]; | 447 llvm::SmallBitVector TypeToRegisterSet[IceType_NUM]; |
466 llvm::SmallBitVector RegisterAliases[RegARM32::Reg_NUM]; | 448 llvm::SmallBitVector RegisterAliases[RegARM32::Reg_NUM]; |
467 llvm::SmallBitVector ScratchRegs; | 449 llvm::SmallBitVector ScratchRegs; |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 | 541 |
560 private: | 542 private: |
561 ~TargetHeaderARM32() = default; | 543 ~TargetHeaderARM32() = default; |
562 | 544 |
563 TargetARM32Features CPUFeatures; | 545 TargetARM32Features CPUFeatures; |
564 }; | 546 }; |
565 | 547 |
566 } // end of namespace Ice | 548 } // end of namespace Ice |
567 | 549 |
568 #endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_H | 550 #endif // SUBZERO_SRC_ICETARGETLOWERINGARM32_H |
OLD | NEW |