OLD | NEW |
---|---|
1 // | 1 // |
2 // The Subzero Code Generator | 2 // The Subzero Code Generator |
3 // | 3 // |
4 // This file is distributed under the University of Illinois Open Source | 4 // This file is distributed under the University of Illinois Open Source |
5 // License. See LICENSE.TXT for details. | 5 // License. See LICENSE.TXT for details. |
6 // | 6 // |
7 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
8 /// | 8 /// |
9 /// \file | 9 /// \file |
10 /// \brief Implements the TargetLoweringMIPS32 class, which consists almost | 10 /// \brief Implements the TargetLoweringMIPS32 class, which consists almost |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
57 namespace Ice { | 57 namespace Ice { |
58 namespace MIPS32 { | 58 namespace MIPS32 { |
59 | 59 |
60 using llvm::isInt; | 60 using llvm::isInt; |
61 | 61 |
62 namespace { | 62 namespace { |
63 | 63 |
64 // The maximum number of arguments to pass in GPR registers. | 64 // The maximum number of arguments to pass in GPR registers. |
65 constexpr uint32_t MIPS32_MAX_GPR_ARG = 4; | 65 constexpr uint32_t MIPS32_MAX_GPR_ARG = 4; |
66 | 66 |
67 std::array<RegNumT, MIPS32_MAX_GPR_ARG> GPRArgInitializer; | |
68 std::array<RegNumT, MIPS32_MAX_GPR_ARG / 2> I64ArgInitializer; | |
69 | |
70 constexpr uint32_t MIPS32_MAX_FP_ARG = 2; | |
71 | |
72 std::array<RegNumT, MIPS32_MAX_FP_ARG> FP32ArgInitializer; | |
73 std::array<RegNumT, MIPS32_MAX_FP_ARG> FP64ArgInitializer; | |
74 | |
67 const char *getRegClassName(RegClass C) { | 75 const char *getRegClassName(RegClass C) { |
68 auto ClassNum = static_cast<RegClassMIPS32>(C); | 76 auto ClassNum = static_cast<RegClassMIPS32>(C); |
69 assert(ClassNum < RCMIPS32_NUM); | 77 assert(ClassNum < RCMIPS32_NUM); |
70 switch (ClassNum) { | 78 switch (ClassNum) { |
71 default: | 79 default: |
72 assert(C < RC_Target); | 80 assert(C < RC_Target); |
73 return regClassString(C); | 81 return regClassString(C); |
74 // Add handling of new register classes below. | 82 // Add handling of new register classes below. |
75 } | 83 } |
76 } | 84 } |
(...skipping 21 matching lines...) Expand all Loading... | |
98 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 106 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ |
99 for (SizeT RegAlias : alias_init) { \ | 107 for (SizeT RegAlias : alias_init) { \ |
100 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ | 108 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ |
101 "Duplicate alias for " #val); \ | 109 "Duplicate alias for " #val); \ |
102 RegisterAliases[RegMIPS32::val].set(RegAlias); \ | 110 RegisterAliases[RegMIPS32::val].set(RegAlias); \ |
103 } \ | 111 } \ |
104 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 112 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ |
105 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); | 113 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); |
106 REGMIPS32_TABLE; | 114 REGMIPS32_TABLE; |
107 #undef X | 115 #undef X |
116 | |
117 // TODO(mohit.bhakkad): Change these inits once we provide argument related | |
118 // field in register tables | |
119 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG; i++) | |
120 GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i); | |
121 | |
122 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG / 2; i++) | |
123 I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i); | |
124 | |
125 for (size_t i = 0; i < MIPS32_MAX_FP_ARG; i++) { | |
126 FP32ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12 + i * 2); | |
127 FP64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12F13 + i); | |
128 } | |
129 | |
108 TypeToRegisterSet[IceType_void] = InvalidRegisters; | 130 TypeToRegisterSet[IceType_void] = InvalidRegisters; |
109 TypeToRegisterSet[IceType_i1] = IntegerRegisters; | 131 TypeToRegisterSet[IceType_i1] = IntegerRegisters; |
110 TypeToRegisterSet[IceType_i8] = IntegerRegisters; | 132 TypeToRegisterSet[IceType_i8] = IntegerRegisters; |
111 TypeToRegisterSet[IceType_i16] = IntegerRegisters; | 133 TypeToRegisterSet[IceType_i16] = IntegerRegisters; |
112 TypeToRegisterSet[IceType_i32] = IntegerRegisters; | 134 TypeToRegisterSet[IceType_i32] = IntegerRegisters; |
113 TypeToRegisterSet[IceType_i64] = IntegerRegisters; | 135 TypeToRegisterSet[IceType_i64] = IntegerRegisters; |
114 TypeToRegisterSet[IceType_f32] = Float32Registers; | 136 TypeToRegisterSet[IceType_f32] = Float32Registers; |
115 TypeToRegisterSet[IceType_f64] = Float64Registers; | 137 TypeToRegisterSet[IceType_f64] = Float64Registers; |
116 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; | 138 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; |
117 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; | 139 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; |
(...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
399 return; | 421 return; |
400 } else { | 422 } else { |
401 int32_t Offset = Var->getStackOffset(); | 423 int32_t Offset = Var->getStackOffset(); |
402 Str << Offset; | 424 Str << Offset; |
403 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); | 425 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); |
404 Str << ")"; | 426 Str << ")"; |
405 } | 427 } |
406 UnimplementedError(getFlags()); | 428 UnimplementedError(getFlags()); |
407 } | 429 } |
408 | 430 |
431 // For now CallingConv takes care of only i32,f32 and f64 types | |
432 // TODO(mohit.bhakkad): Add support for other types (struct as arg, functions | |
Jim Stichnoth
2016/06/10 23:03:46
Fortunately, the PNaCl ABI only allows primitive (
| |
433 // returning struct) | |
434 TargetMIPS32::CallingConv::CallingConv() | |
435 : GPRegsUsed(RegMIPS32::Reg_NUM), | |
436 GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()), | |
437 I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()), | |
438 VFPRegsUsed(RegMIPS32::Reg_NUM), | |
439 FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()), | |
440 FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()), | |
441 UseFPRegs(false) {} | |
Jim Stichnoth
2016/06/10 23:03:46
"UseFPRegs(false)" will be unnecessary when declar
| |
442 | |
443 // In MIPS O32 abi FP argument registers can be used only if first argument is | |
444 // of type float/double. UseFPRegs flag is used to care of that. Also FP arg | |
445 // registers can be used only for first 2 arguments, so we require argument | |
446 // number to make register allocation decisions. | |
447 bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo, | |
448 RegNumT *Reg) { | |
449 if (isScalarIntegerType(Ty)) | |
450 return argInGPR(Ty, Reg); | |
451 else if (isScalarFloatingType(Ty)) { | |
Jim Stichnoth
2016/06/10 23:03:46
You don't need "else if" when the previous branch
| |
452 if (ArgNo == 0) { | |
453 UseFPRegs = true; | |
454 return argInVFP(Ty, Reg); | |
455 } else { | |
456 if (UseFPRegs && ArgNo == 1) { | |
457 UseFPRegs = false; | |
458 return argInVFP(Ty, Reg); | |
459 } else | |
460 return argInGPR(Ty, Reg); | |
461 } | |
462 } else { | |
463 UnimplementedError(getFlags()); | |
464 return false; | |
465 } | |
466 } | |
467 | |
468 bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) { | |
469 CfgVector<RegNumT> *Source; | |
470 | |
471 switch (Ty) { | |
472 default: { | |
473 UnimplementedError(getFlags()); | |
474 return false; | |
475 } break; | |
476 case IceType_i32: | |
477 case IceType_f32: { | |
478 Source = &GPRArgs; | |
479 } break; | |
480 case IceType_i64: | |
481 case IceType_f64: { | |
482 Source = &I64Args; | |
483 } break; | |
484 } | |
485 | |
486 discardUnavailableGPRsAndTheirAliases(Source); | |
487 | |
488 if (Source->empty()) { | |
489 GPRegsUsed.set(); | |
490 return false; | |
491 } | |
492 | |
493 *Reg = Source->back(); | |
494 // Note that we don't Source->pop_back() here. This is intentional. Notice how | |
495 // we mark all of Reg's aliases as Used. So, for the next argument, | |
496 // Source->back() is marked as unavailable, and it is thus implicitly popped | |
497 // from the stack. | |
498 GPRegsUsed |= RegisterAliases[*Reg]; | |
499 return true; | |
500 } | |
501 | |
502 inline void TargetMIPS32::CallingConv::discardNextGPRAndItsAliases( | |
503 CfgVector<RegNumT> *Regs) { | |
504 GPRegsUsed |= RegisterAliases[Regs->back()]; | |
505 Regs->pop_back(); | |
506 } | |
507 | |
508 // GPR are not packed when passing parameters. Thus, a function foo(i32, i64, | |
509 // i32) will have the first argument in a0, the second in a2-a3, and the third | |
510 // on the stack. To model this behavior, whenever we pop a register from Regs, | |
511 // we remove all of its aliases from the pool of available GPRs. This has the | |
512 // effect of computing the "closure" on the GPR registers. | |
513 void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases( | |
514 CfgVector<RegNumT> *Regs) { | |
515 while (!Regs->empty() && GPRegsUsed[Regs->back()]) { | |
516 discardNextGPRAndItsAliases(Regs); | |
517 } | |
518 } | |
519 | |
520 bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) { | |
521 CfgVector<RegNumT> *Source; | |
522 | |
523 switch (Ty) { | |
524 default: { | |
525 UnimplementedError(getFlags()); | |
526 return false; | |
527 } break; | |
528 case IceType_f32: { | |
529 Source = &FP32Args; | |
530 } break; | |
531 case IceType_f64: { | |
532 Source = &FP64Args; | |
533 } break; | |
534 } | |
535 | |
536 discardUnavailableVFPRegsAndTheirAliases(Source); | |
537 | |
538 if (Source->empty()) { | |
539 VFPRegsUsed.set(); | |
540 return false; | |
541 } | |
542 | |
543 *Reg = Source->back(); | |
544 VFPRegsUsed |= RegisterAliases[*Reg]; | |
545 | |
546 // In MIPS O32 abi if fun argumets are (f32, i32) then one can not use reg_a0 | |
Jim Stichnoth
2016/06/10 23:03:46
arguments
| |
547 // for second argument even though its free. f32 arg goes in reg_f12, i32 arg | |
Jim Stichnoth
2016/06/10 23:03:46
it's
| |
548 // goes in reg_a1. Similarly if arguments are (f64, i32) second argumnent goes | |
549 // in reg_a3 and a0, a1 are not used. | |
550 Source = &GPRArgs; | |
551 // Discard one GPR reg for f32(4 bytes), two for f64(4 + 4 bytes) | |
552 discardNextGPRAndItsAliases(Source); | |
553 if (Ty == IceType_f64) | |
554 discardNextGPRAndItsAliases(Source); | |
555 | |
556 return true; | |
557 } | |
558 | |
559 void TargetMIPS32::CallingConv::discardUnavailableVFPRegsAndTheirAliases( | |
560 CfgVector<RegNumT> *Regs) { | |
561 while (!Regs->empty() && VFPRegsUsed[Regs->back()]) { | |
562 Regs->pop_back(); | |
563 } | |
564 } | |
565 | |
409 void TargetMIPS32::lowerArguments() { | 566 void TargetMIPS32::lowerArguments() { |
410 VarList &Args = Func->getArgs(); | 567 VarList &Args = Func->getArgs(); |
411 // We are only handling integer registers for now. The Mips o32 ABI is | 568 // We are only handling integer registers for now. The Mips o32 ABI is |
412 // somewhat complex but will be implemented in its totality through follow | 569 // somewhat complex but will be implemented in its totality through follow |
413 // on patches. | 570 // on patches. |
414 // | 571 // |
415 unsigned NumGPRRegsUsed = 0; | 572 unsigned NumGPRRegsUsed = 0; |
416 // For each register argument, replace Arg in the argument list with the | 573 // For each register argument, replace Arg in the argument list with the |
417 // home register. Then generate an instruction in the prolog to copy the | 574 // home register. Then generate an instruction in the prolog to copy the |
418 // home register to the assigned location of Arg. | 575 // home register to the assigned location of Arg. |
(...skipping 1295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1714 Str << "\t.set\t" | 1871 Str << "\t.set\t" |
1715 << "nomips16\n"; | 1872 << "nomips16\n"; |
1716 } | 1873 } |
1717 | 1874 |
1718 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 1875 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; |
1719 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 1876 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; |
1720 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 1877 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; |
1721 | 1878 |
1722 } // end of namespace MIPS32 | 1879 } // end of namespace MIPS32 |
1723 } // end of namespace Ice | 1880 } // end of namespace Ice |
OLD | NEW |