 Chromium Code Reviews
 Chromium Code Reviews Issue 2027773002:
  Subzero, MIPS32: Handling floating point instructions fadd, fsub, fmul, fdiv  (Closed) 
  Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
    
  
    Issue 2027773002:
  Subzero, MIPS32: Handling floating point instructions fadd, fsub, fmul, fdiv  (Closed) 
  Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master| 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 } | 
| 77 | 85 | 
| 86 // Stack alignment | |
| 87 constexpr uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 8; | |
| 88 | |
| 89 // Value is in bytes. Return Value adjusted to the next highest multiple of the | |
| 90 // stack alignment required for the given type. | |
| 91 uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { | |
| 92 size_t typeAlignInBytes = typeWidthInBytes(Ty); | |
| 93 if (isVectorType(Ty)) | |
| 94 UnimplementedError(getFlags()); | |
| 95 return Utils::applyAlignment(Value, typeAlignInBytes); | |
| 96 } | |
| 97 | |
| 78 } // end of anonymous namespace | 98 } // end of anonymous namespace | 
| 79 | 99 | 
| 80 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} | 100 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} | 
| 81 | 101 | 
| 82 void TargetMIPS32::staticInit(GlobalContext *Ctx) { | 102 void TargetMIPS32::staticInit(GlobalContext *Ctx) { | 
| 83 (void)Ctx; | 103 (void)Ctx; | 
| 84 RegNumT::setLimit(RegMIPS32::Reg_NUM); | 104 RegNumT::setLimit(RegMIPS32::Reg_NUM); | 
| 85 SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM); | 105 SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM); | 
| 86 SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM); | 106 SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM); | 
| 87 SmallBitVector Float32Registers(RegMIPS32::Reg_NUM); | 107 SmallBitVector Float32Registers(RegMIPS32::Reg_NUM); | 
| (...skipping 10 matching lines...) Expand all Loading... | |
| 98 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 118 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 
| 99 for (SizeT RegAlias : alias_init) { \ | 119 for (SizeT RegAlias : alias_init) { \ | 
| 100 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ | 120 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ | 
| 101 "Duplicate alias for " #val); \ | 121 "Duplicate alias for " #val); \ | 
| 102 RegisterAliases[RegMIPS32::val].set(RegAlias); \ | 122 RegisterAliases[RegMIPS32::val].set(RegAlias); \ | 
| 103 } \ | 123 } \ | 
| 104 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 124 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 
| 105 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); | 125 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); | 
| 106 REGMIPS32_TABLE; | 126 REGMIPS32_TABLE; | 
| 107 #undef X | 127 #undef X | 
| 128 | |
| 129 // TODO(mohit.bhakkad): Change these inits once we provide argument related | |
| 130 // field in register tables | |
| 131 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG; i++) | |
| 132 GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i); | |
| 133 | |
| 134 for (size_t i = 0; i < MIPS32_MAX_GPR_ARG / 2; i++) | |
| 135 I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i); | |
| 136 | |
| 137 for (size_t i = 0; i < MIPS32_MAX_FP_ARG; i++) { | |
| 138 FP32ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12 + i * 2); | |
| 139 FP64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12F13 + i); | |
| 140 } | |
| 141 | |
| 108 TypeToRegisterSet[IceType_void] = InvalidRegisters; | 142 TypeToRegisterSet[IceType_void] = InvalidRegisters; | 
| 109 TypeToRegisterSet[IceType_i1] = IntegerRegisters; | 143 TypeToRegisterSet[IceType_i1] = IntegerRegisters; | 
| 110 TypeToRegisterSet[IceType_i8] = IntegerRegisters; | 144 TypeToRegisterSet[IceType_i8] = IntegerRegisters; | 
| 111 TypeToRegisterSet[IceType_i16] = IntegerRegisters; | 145 TypeToRegisterSet[IceType_i16] = IntegerRegisters; | 
| 112 TypeToRegisterSet[IceType_i32] = IntegerRegisters; | 146 TypeToRegisterSet[IceType_i32] = IntegerRegisters; | 
| 113 TypeToRegisterSet[IceType_i64] = IntegerRegisters; | 147 TypeToRegisterSet[IceType_i64] = IntegerRegisters; | 
| 114 TypeToRegisterSet[IceType_f32] = Float32Registers; | 148 TypeToRegisterSet[IceType_f32] = Float32Registers; | 
| 115 TypeToRegisterSet[IceType_f64] = Float64Registers; | 149 TypeToRegisterSet[IceType_f64] = Float64Registers; | 
| 116 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; | 150 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; | 
| 117 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; | 151 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; | 
| 118 TypeToRegisterSet[IceType_v16i1] = VectorRegisters; | 152 TypeToRegisterSet[IceType_v16i1] = VectorRegisters; | 
| 119 TypeToRegisterSet[IceType_v16i8] = VectorRegisters; | 153 TypeToRegisterSet[IceType_v16i8] = VectorRegisters; | 
| 120 TypeToRegisterSet[IceType_v8i16] = VectorRegisters; | 154 TypeToRegisterSet[IceType_v8i16] = VectorRegisters; | 
| 121 TypeToRegisterSet[IceType_v4i32] = VectorRegisters; | 155 TypeToRegisterSet[IceType_v4i32] = VectorRegisters; | 
| 122 TypeToRegisterSet[IceType_v4f32] = VectorRegisters; | 156 TypeToRegisterSet[IceType_v4f32] = VectorRegisters; | 
| 123 | 157 | 
| 124 for (size_t i = 0; i < llvm::array_lengthof(TypeToRegisterSet); ++i) | 158 for (size_t i = 0; i < llvm::array_lengthof(TypeToRegisterSet); ++i) | 
| 125 TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i]; | 159 TypeToRegisterSetUnfiltered[i] = TypeToRegisterSet[i]; | 
| 126 | 160 | 
| 127 filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet, | 161 filterTypeToRegisterSet(Ctx, RegMIPS32::Reg_NUM, TypeToRegisterSet, | 
| 128 llvm::array_lengthof(TypeToRegisterSet), | 162 llvm::array_lengthof(TypeToRegisterSet), | 
| 129 RegMIPS32::getRegName, getRegClassName); | 163 RegMIPS32::getRegName, getRegClassName); | 
| 130 } | 164 } | 
| 131 | 165 | 
| 166 void TargetMIPS32::findMaxStackOutArgsSize() { | |
| 167 // MinNeededOutArgsBytes should be updated if the Target ever creates a | |
| 168 // high-level InstCall that requires more stack bytes. | |
| 169 constexpr size_t MinNeededOutArgsBytes = 16; | |
| 170 MaxOutArgsSizeBytes = MinNeededOutArgsBytes; | |
| 171 for (CfgNode *Node : Func->getNodes()) { | |
| 172 Context.init(Node); | |
| 173 while (!Context.atEnd()) { | |
| 174 PostIncrLoweringContext PostIncrement(Context); | |
| 175 Inst *CurInstr = iteratorToInst(Context.getCur()); | |
| 176 if (auto *Call = llvm::dyn_cast<InstCall>(CurInstr)) { | |
| 177 SizeT OutArgsSizeBytes = getCallStackArgumentsSizeBytes(Call); | |
| 178 MaxOutArgsSizeBytes = std::max(MaxOutArgsSizeBytes, OutArgsSizeBytes); | |
| 179 } | |
| 180 } | |
| 181 } | |
| 182 } | |
| 183 | |
| 132 void TargetMIPS32::translateO2() { | 184 void TargetMIPS32::translateO2() { | 
| 133 TimerMarker T(TimerStack::TT_O2, Func); | 185 TimerMarker T(TimerStack::TT_O2, Func); | 
| 134 | 186 | 
| 135 // TODO(stichnot): share passes with X86? | 187 // TODO(stichnot): share passes with X86? | 
| 136 // https://code.google.com/p/nativeclient/issues/detail?id=4094 | 188 // https://code.google.com/p/nativeclient/issues/detail?id=4094 | 
| 137 genTargetHelperCalls(); | 189 genTargetHelperCalls(); | 
| 138 | 190 | 
| 191 findMaxStackOutArgsSize(); | |
| 192 | |
| 139 // Merge Alloca instructions, and lay out the stack. | 193 // Merge Alloca instructions, and lay out the stack. | 
| 140 static constexpr bool SortAndCombineAllocas = false; | 194 static constexpr bool SortAndCombineAllocas = false; | 
| 141 Func->processAllocas(SortAndCombineAllocas); | 195 Func->processAllocas(SortAndCombineAllocas); | 
| 142 Func->dump("After Alloca processing"); | 196 Func->dump("After Alloca processing"); | 
| 143 | 197 | 
| 144 if (!getFlags().getEnablePhiEdgeSplit()) { | 198 if (!getFlags().getEnablePhiEdgeSplit()) { | 
| 145 // Lower Phi instructions. | 199 // Lower Phi instructions. | 
| 146 Func->placePhiLoads(); | 200 Func->placePhiLoads(); | 
| 147 if (Func->hasError()) | 201 if (Func->hasError()) | 
| 148 return; | 202 return; | 
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 Func->doNopInsertion(); | 284 Func->doNopInsertion(); | 
| 231 } | 285 } | 
| 232 } | 286 } | 
| 233 | 287 | 
| 234 void TargetMIPS32::translateOm1() { | 288 void TargetMIPS32::translateOm1() { | 
| 235 TimerMarker T(TimerStack::TT_Om1, Func); | 289 TimerMarker T(TimerStack::TT_Om1, Func); | 
| 236 | 290 | 
| 237 // TODO: share passes with X86? | 291 // TODO: share passes with X86? | 
| 238 genTargetHelperCalls(); | 292 genTargetHelperCalls(); | 
| 239 | 293 | 
| 294 findMaxStackOutArgsSize(); | |
| 295 | |
| 240 // Do not merge Alloca instructions, and lay out the stack. | 296 // Do not merge Alloca instructions, and lay out the stack. | 
| 241 static constexpr bool SortAndCombineAllocas = false; | 297 static constexpr bool SortAndCombineAllocas = false; | 
| 242 Func->processAllocas(SortAndCombineAllocas); | 298 Func->processAllocas(SortAndCombineAllocas); | 
| 243 Func->dump("After Alloca processing"); | 299 Func->dump("After Alloca processing"); | 
| 244 | 300 | 
| 245 Func->placePhiLoads(); | 301 Func->placePhiLoads(); | 
| 246 if (Func->hasError()) | 302 if (Func->hasError()) | 
| 247 return; | 303 return; | 
| 248 Func->placePhiStores(); | 304 Func->placePhiStores(); | 
| 249 if (Func->hasError()) | 305 if (Func->hasError()) | 
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 396 const Type FrameSPTy = IceType_i32; | 452 const Type FrameSPTy = IceType_i32; | 
| 397 if (Var->hasReg()) { | 453 if (Var->hasReg()) { | 
| 398 Str << '$' << getRegName(Var->getRegNum(), Var->getType()); | 454 Str << '$' << getRegName(Var->getRegNum(), Var->getType()); | 
| 399 return; | 455 return; | 
| 400 } else { | 456 } else { | 
| 401 int32_t Offset = Var->getStackOffset(); | 457 int32_t Offset = Var->getStackOffset(); | 
| 402 Str << Offset; | 458 Str << Offset; | 
| 403 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); | 459 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); | 
| 404 Str << ")"; | 460 Str << ")"; | 
| 405 } | 461 } | 
| 462 // UnimplementedError(getFlags()); | |
| 
Jim Stichnoth
2016/06/13 20:14:19
remove this
 | |
| 463 } | |
| 464 | |
| 465 TargetMIPS32::CallingConv::CallingConv() | |
| 466 : GPRegsUsed(RegMIPS32::Reg_NUM), | |
| 467 GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()), | |
| 468 I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()), | |
| 469 VFPRegsUsed(RegMIPS32::Reg_NUM), | |
| 470 FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()), | |
| 471 FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()) {} | |
| 472 | |
| 473 // In MIPS O32 abi FP argument registers can be used only if first argument is | |
| 474 // of type float/double. UseFPRegs flag is used to care of that. Also FP arg | |
| 475 // registers can be used only for first 2 arguments, so we require argument | |
| 476 // number to make register allocation decisions. | |
| 477 bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo, | |
| 478 RegNumT *Reg) { | |
| 479 if (isScalarIntegerType(Ty)) | |
| 480 return argInGPR(Ty, Reg); | |
| 481 if (isScalarFloatingType(Ty)) { | |
| 482 if (ArgNo == 0) { | |
| 483 UseFPRegs = true; | |
| 484 return argInVFP(Ty, Reg); | |
| 485 } | |
| 486 if (UseFPRegs && ArgNo == 1) { | |
| 487 UseFPRegs = false; | |
| 488 return argInVFP(Ty, Reg); | |
| 489 } | |
| 490 return argInGPR(Ty, Reg); | |
| 491 } | |
| 406 UnimplementedError(getFlags()); | 492 UnimplementedError(getFlags()); | 
| 493 return false; | |
| 494 } | |
| 495 | |
| 496 bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) { | |
| 497 CfgVector<RegNumT> *Source; | |
| 498 | |
| 499 switch (Ty) { | |
| 500 default: { | |
| 501 UnimplementedError(getFlags()); | |
| 502 return false; | |
| 503 } break; | |
| 504 case IceType_i32: | |
| 505 case IceType_f32: { | |
| 506 Source = &GPRArgs; | |
| 507 } break; | |
| 508 case IceType_i64: | |
| 509 case IceType_f64: { | |
| 510 Source = &I64Args; | |
| 511 } break; | |
| 512 } | |
| 513 | |
| 514 discardUnavailableGPRsAndTheirAliases(Source); | |
| 515 | |
| 516 if (Source->empty()) { | |
| 517 GPRegsUsed.set(); | |
| 518 return false; | |
| 519 } | |
| 520 | |
| 521 *Reg = Source->back(); | |
| 522 // Note that we don't Source->pop_back() here. This is intentional. Notice how | |
| 523 // we mark all of Reg's aliases as Used. So, for the next argument, | |
| 524 // Source->back() is marked as unavailable, and it is thus implicitly popped | |
| 525 // from the stack. | |
| 526 GPRegsUsed |= RegisterAliases[*Reg]; | |
| 527 return true; | |
| 528 } | |
| 529 | |
| 530 inline void TargetMIPS32::CallingConv::discardNextGPRAndItsAliases( | |
| 531 CfgVector<RegNumT> *Regs) { | |
| 532 GPRegsUsed |= RegisterAliases[Regs->back()]; | |
| 533 Regs->pop_back(); | |
| 534 } | |
| 535 | |
| 536 // GPR are not packed when passing parameters. Thus, a function foo(i32, i64, | |
| 537 // i32) will have the first argument in a0, the second in a2-a3, and the third | |
| 538 // on the stack. To model this behavior, whenever we pop a register from Regs, | |
| 539 // we remove all of its aliases from the pool of available GPRs. This has the | |
| 540 // effect of computing the "closure" on the GPR registers. | |
| 541 void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases( | |
| 542 CfgVector<RegNumT> *Regs) { | |
| 543 while (!Regs->empty() && GPRegsUsed[Regs->back()]) { | |
| 544 discardNextGPRAndItsAliases(Regs); | |
| 545 } | |
| 546 } | |
| 547 | |
| 548 bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) { | |
| 549 CfgVector<RegNumT> *Source; | |
| 550 | |
| 551 switch (Ty) { | |
| 552 default: { | |
| 553 UnimplementedError(getFlags()); | |
| 554 return false; | |
| 555 } break; | |
| 556 case IceType_f32: { | |
| 557 Source = &FP32Args; | |
| 558 } break; | |
| 559 case IceType_f64: { | |
| 560 Source = &FP64Args; | |
| 561 } break; | |
| 562 } | |
| 563 | |
| 564 discardUnavailableVFPRegsAndTheirAliases(Source); | |
| 565 | |
| 566 if (Source->empty()) { | |
| 567 VFPRegsUsed.set(); | |
| 568 return false; | |
| 569 } | |
| 570 | |
| 571 *Reg = Source->back(); | |
| 572 VFPRegsUsed |= RegisterAliases[*Reg]; | |
| 573 | |
| 574 // In MIPS O32 abi if fun arguments are (f32, i32) then one can not use reg_a0 | |
| 575 // for second argument even though it's free. f32 arg goes in reg_f12, i32 arg | |
| 576 // goes in reg_a1. Similarly if arguments are (f64, i32) second argument goes | |
| 577 // in reg_a3 and a0, a1 are not used. | |
| 578 Source = &GPRArgs; | |
| 579 // Discard one GPR reg for f32(4 bytes), two for f64(4 + 4 bytes) | |
| 580 discardNextGPRAndItsAliases(Source); | |
| 581 if (Ty == IceType_f64) | |
| 582 discardNextGPRAndItsAliases(Source); | |
| 583 | |
| 584 return true; | |
| 585 } | |
| 586 | |
| 587 void TargetMIPS32::CallingConv::discardUnavailableVFPRegsAndTheirAliases( | |
| 588 CfgVector<RegNumT> *Regs) { | |
| 589 while (!Regs->empty() && VFPRegsUsed[Regs->back()]) { | |
| 590 Regs->pop_back(); | |
| 591 } | |
| 407 } | 592 } | 
| 408 | 593 | 
| 409 void TargetMIPS32::lowerArguments() { | 594 void TargetMIPS32::lowerArguments() { | 
| 410 VarList &Args = Func->getArgs(); | 595 VarList &Args = Func->getArgs(); | 
| 411 // We are only handling integer registers for now. The Mips o32 ABI is | 596 TargetMIPS32::CallingConv CC; | 
| 412 // somewhat complex but will be implemented in its totality through follow | 597 | 
| 413 // on patches. | 598 // For each register argument, replace Arg in the argument list with the home | 
| 414 // | 599 // register. Then generate an instruction in the prolog to copy the home | 
| 415 unsigned NumGPRRegsUsed = 0; | 600 // register to the assigned location of Arg. | 
| 416 // 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 | |
| 418 // home register to the assigned location of Arg. | |
| 419 Context.init(Func->getEntryNode()); | 601 Context.init(Func->getEntryNode()); | 
| 420 Context.setInsertPoint(Context.getCur()); | 602 Context.setInsertPoint(Context.getCur()); | 
| 603 | |
| 421 for (SizeT I = 0, E = Args.size(); I < E; ++I) { | 604 for (SizeT I = 0, E = Args.size(); I < E; ++I) { | 
| 422 Variable *Arg = Args[I]; | 605 Variable *Arg = Args[I]; | 
| 423 Type Ty = Arg->getType(); | 606 Type Ty = Arg->getType(); | 
| 424 // TODO(rkotler): handle float/vector types. | 607 RegNumT RegNum; | 
| 425 if (isVectorType(Ty)) { | 608 if (!CC.argInReg(Ty, I, &RegNum)) { | 
| 426 UnimplementedError(getFlags()); | |
| 427 continue; | 609 continue; | 
| 428 } | 610 } | 
| 429 if (isFloatingType(Ty)) { | 611 Variable *RegisterArg = Func->makeVariable(Ty); | 
| 430 UnimplementedError(getFlags()); | 612 if (BuildDefs::dump()) { | 
| 613 RegisterArg->setName(Func, "home_reg:" + Arg->getName()); | |
| 614 } | |
| 615 RegisterArg->setIsArg(); | |
| 616 Arg->setIsArg(false); | |
| 617 Args[I] = RegisterArg; | |
| 618 switch (Ty) { | |
| 619 default: { RegisterArg->setRegNum(RegNum); } break; | |
| 620 case IceType_i64: { | |
| 621 auto *RegisterArg64 = llvm::cast<Variable64On32>(RegisterArg); | |
| 622 RegisterArg64->initHiLo(Func); | |
| 623 RegisterArg64->getLo()->setRegNum( | |
| 624 RegNumT::fixme(RegMIPS32::getI64PairFirstGPRNum(RegNum))); | |
| 625 RegisterArg64->getHi()->setRegNum( | |
| 626 RegNumT::fixme(RegMIPS32::getI64PairSecondGPRNum(RegNum))); | |
| 627 } break; | |
| 628 } | |
| 629 Context.insert<InstAssign>(Arg, RegisterArg); | |
| 630 } | |
| 631 } | |
| 632 | |
| 633 Type TargetMIPS32::stackSlotType() { return IceType_i32; } | |
| 634 | |
| 635 // Helper function for addProlog(). | |
| 636 // | |
| 637 // This assumes Arg is an argument passed on the stack. This sets the frame | |
| 638 // offset for Arg and updates InArgsSizeBytes according to Arg's width. For an | |
| 639 // I64 arg that has been split into Lo and Hi components, it calls itself | |
| 640 // recursively on the components, taking care to handle Lo first because of the | |
| 641 // little-endian architecture. Lastly, this function generates an instruction | |
| 642 // to copy Arg into its assigned register if applicable. | |
| 643 void TargetMIPS32::finishArgumentLowering(Variable *Arg, Variable *FramePtr, | |
| 644 size_t BasicFrameOffset, | |
| 645 size_t *InArgsSizeBytes) { | |
| 646 const Type Ty = Arg->getType(); | |
| 647 *InArgsSizeBytes = applyStackAlignmentTy(*InArgsSizeBytes, Ty); | |
| 648 | |
| 649 if (auto *Arg64On32 = llvm::dyn_cast<Variable64On32>(Arg)) { | |
| 650 Variable *const Lo = Arg64On32->getLo(); | |
| 651 Variable *const Hi = Arg64On32->getHi(); | |
| 652 finishArgumentLowering(Lo, FramePtr, BasicFrameOffset, InArgsSizeBytes); | |
| 653 finishArgumentLowering(Hi, FramePtr, BasicFrameOffset, InArgsSizeBytes); | |
| 654 return; | |
| 655 } | |
| 656 assert(Ty != IceType_i64); | |
| 657 | |
| 658 const int32_t ArgStackOffset = BasicFrameOffset + *InArgsSizeBytes; | |
| 659 *InArgsSizeBytes += typeWidthInBytesOnStack(Ty); | |
| 660 | |
| 661 if (!Arg->hasReg()) { | |
| 662 Arg->setStackOffset(ArgStackOffset); | |
| 663 return; | |
| 664 } | |
| 665 | |
| 666 // If the argument variable has been assigned a register, we need to copy the | |
| 667 // value from the stack slot. | |
| 668 Variable *Parameter = Func->makeVariable(Ty); | |
| 669 Parameter->setMustNotHaveReg(); | |
| 670 Parameter->setStackOffset(ArgStackOffset); | |
| 671 _mov(Arg, Parameter); | |
| 672 } | |
| 673 | |
| 674 void TargetMIPS32::addProlog(CfgNode *Node) { | |
| 675 // Stack frame layout: | |
| 676 // | |
| 677 // +------------------------+ | |
| 678 // | 1. preserved registers | | |
| 679 // +------------------------+ | |
| 680 // | 2. padding | | |
| 681 // +------------------------+ | |
| 682 // | 3. global spill area | | |
| 683 // +------------------------+ | |
| 684 // | 4. padding | | |
| 685 // +------------------------+ | |
| 686 // | 5. local spill area | | |
| 687 // +------------------------+ | |
| 688 // | 6. padding | | |
| 689 // +------------------------+ | |
| 690 // | 7. allocas | | |
| 691 // +------------------------+ | |
| 692 // | 8. padding | | |
| 693 // +------------------------+ | |
| 694 // | 9. out args | | |
| 695 // +------------------------+ <--- StackPointer | |
| 696 // | |
| 697 // The following variables record the size in bytes of the given areas: | |
| 698 // * PreservedRegsSizeBytes: area 1 | |
| 699 // * SpillAreaPaddingBytes: area 2 | |
| 700 // * GlobalsSize: area 3 | |
| 701 // * GlobalsAndSubsequentPaddingSize: areas 3 - 4 | |
| 702 // * LocalsSpillAreaSize: area 5 | |
| 703 // * SpillAreaSizeBytes: areas 2 - 9 | |
| 704 // * maxOutArgsSizeBytes(): area 9 | |
| 705 | |
| 706 Context.init(Node); | |
| 707 Context.setInsertPoint(Context.getCur()); | |
| 708 | |
| 709 SmallBitVector CalleeSaves = getRegisterSet(RegSet_CalleeSave, RegSet_None); | |
| 710 RegsUsed = SmallBitVector(CalleeSaves.size()); | |
| 711 | |
| 712 VarList SortedSpilledVariables; | |
| 713 | |
| 714 size_t GlobalsSize = 0; | |
| 715 // If there is a separate locals area, this represents that area. Otherwise | |
| 716 // it counts any variable not counted by GlobalsSize. | |
| 717 SpillAreaSizeBytes = 0; | |
| 718 // If there is a separate locals area, this specifies the alignment for it. | |
| 719 uint32_t LocalsSlotsAlignmentBytes = 0; | |
| 720 // The entire spill locations area gets aligned to largest natural alignment | |
| 721 // of the variables that have a spill slot. | |
| 722 uint32_t SpillAreaAlignmentBytes = 0; | |
| 723 // For now, we don't have target-specific variables that need special | |
| 724 // treatment (no stack-slot-linked SpillVariable type). | |
| 725 std::function<bool(Variable *)> TargetVarHook = [](Variable *Var) { | |
| 726 static constexpr bool AssignStackSlot = false; | |
| 727 static constexpr bool DontAssignStackSlot = !AssignStackSlot; | |
| 728 if (llvm::isa<Variable64On32>(Var)) { | |
| 729 return DontAssignStackSlot; | |
| 730 } | |
| 731 return AssignStackSlot; | |
| 732 }; | |
| 733 | |
| 734 // Compute the list of spilled variables and bounds for GlobalsSize, etc. | |
| 735 getVarStackSlotParams(SortedSpilledVariables, RegsUsed, &GlobalsSize, | |
| 736 &SpillAreaSizeBytes, &SpillAreaAlignmentBytes, | |
| 737 &LocalsSlotsAlignmentBytes, TargetVarHook); | |
| 738 uint32_t LocalsSpillAreaSize = SpillAreaSizeBytes; | |
| 739 SpillAreaSizeBytes += GlobalsSize; | |
| 740 | |
| 741 PreservedGPRs.reserve(CalleeSaves.size()); | |
| 742 | |
| 743 // Consider FP and RA as callee-save / used as needed. | |
| 744 if (UsesFramePointer) { | |
| 745 if (RegsUsed[RegMIPS32::Reg_FP]) { | |
| 746 llvm::report_fatal_error("Frame pointer has been used."); | |
| 747 } | |
| 748 CalleeSaves[RegMIPS32::Reg_FP] = true; | |
| 749 RegsUsed[RegMIPS32::Reg_FP] = true; | |
| 750 } | |
| 751 if (!MaybeLeafFunc) { | |
| 752 CalleeSaves[RegMIPS32::Reg_RA] = true; | |
| 753 RegsUsed[RegMIPS32::Reg_RA] = true; | |
| 754 } | |
| 755 | |
| 756 // Make two passes over the used registers. The first pass records all the | |
| 757 // used registers -- and their aliases. Then, we figure out which GPR | |
| 758 // registers should be saved. | |
| 759 SmallBitVector ToPreserve(RegMIPS32::Reg_NUM); | |
| 760 for (SizeT i = 0; i < CalleeSaves.size(); ++i) { | |
| 761 if (CalleeSaves[i] && RegsUsed[i]) { | |
| 762 ToPreserve |= RegisterAliases[i]; | |
| 763 } | |
| 764 } | |
| 765 | |
| 766 uint32_t NumCallee = 0; | |
| 767 size_t PreservedRegsSizeBytes = 0; | |
| 768 | |
| 769 // RegClasses is a tuple of | |
| 770 // | |
| 771 // <First Register in Class, Last Register in Class, Vector of Save Registers> | |
| 772 // | |
| 773 // We use this tuple to figure out which register we should save/restore | |
| 774 // during | |
| 775 // prolog/epilog. | |
| 776 using RegClassType = std::tuple<uint32_t, uint32_t, VarList *>; | |
| 777 const RegClassType RegClass = RegClassType( | |
| 778 RegMIPS32::Reg_GPR_First, RegMIPS32::Reg_GPR_Last, &PreservedGPRs); | |
| 779 const uint32_t FirstRegInClass = std::get<0>(RegClass); | |
| 780 const uint32_t LastRegInClass = std::get<1>(RegClass); | |
| 781 VarList *const PreservedRegsInClass = std::get<2>(RegClass); | |
| 782 for (uint32_t Reg = LastRegInClass; Reg > FirstRegInClass; Reg--) { | |
| 783 if (!ToPreserve[Reg]) { | |
| 431 continue; | 784 continue; | 
| 432 } | 785 } | 
| 433 if (Ty == IceType_i64) { | 786 ++NumCallee; | 
| 434 if (NumGPRRegsUsed >= MIPS32_MAX_GPR_ARG) | 787 Variable *PhysicalRegister = getPhysicalRegister(RegNumT::fromInt(Reg)); | 
| 435 continue; | 788 PreservedRegsSizeBytes += | 
| 436 auto RegLo = RegNumT::fixme(RegMIPS32::Reg_A0 + NumGPRRegsUsed); | 789 typeWidthInBytesOnStack(PhysicalRegister->getType()); | 
| 437 auto RegHi = RegNumT::fixme(RegLo + 1); | 790 PreservedRegsInClass->push_back(PhysicalRegister); | 
| 438 ++NumGPRRegsUsed; | 791 } | 
| 439 // Always start i64 registers at an even register, so this may end | 792 | 
| 440 // up padding away a register. | 793 Ctx->statsUpdateRegistersSaved(NumCallee); | 
| 441 if (RegLo % 2 != 0) { | 794 | 
| 442 RegLo = RegNumT::fixme(RegLo + 1); | 795 // Align the variables area. SpillAreaPaddingBytes is the size of the region | 
| 443 ++NumGPRRegsUsed; | 796 // after the preserved registers and before the spill areas. | 
| 444 } | 797 // LocalsSlotsPaddingBytes is the amount of padding between the globals and | 
| 445 // If this leaves us without room to consume another register, | 798 // locals area if they are separate. | 
| 446 // leave any previously speculatively consumed registers as consumed. | 799 assert(SpillAreaAlignmentBytes <= MIPS32_STACK_ALIGNMENT_BYTES); | 
| 447 if (NumGPRRegsUsed >= MIPS32_MAX_GPR_ARG) | 800 (void)MIPS32_STACK_ALIGNMENT_BYTES; | 
| 448 continue; | 801 assert(LocalsSlotsAlignmentBytes <= SpillAreaAlignmentBytes); | 
| 449 // RegHi = RegNumT::fixme(RegMIPS32::Reg_A0 + NumGPRRegsUsed); | 802 uint32_t SpillAreaPaddingBytes = 0; | 
| 450 ++NumGPRRegsUsed; | 803 uint32_t LocalsSlotsPaddingBytes = 0; | 
| 451 Variable *RegisterArg = Func->makeVariable(Ty); | 804 alignStackSpillAreas(PreservedRegsSizeBytes, SpillAreaAlignmentBytes, | 
| 452 auto *RegisterArg64On32 = llvm::cast<Variable64On32>(RegisterArg); | 805 GlobalsSize, LocalsSlotsAlignmentBytes, | 
| 453 if (BuildDefs::dump()) | 806 &SpillAreaPaddingBytes, &LocalsSlotsPaddingBytes); | 
| 454 RegisterArg64On32->setName(Func, "home_reg:" + Arg->getName()); | 807 SpillAreaSizeBytes += SpillAreaPaddingBytes + LocalsSlotsPaddingBytes; | 
| 455 RegisterArg64On32->initHiLo(Func); | 808 uint32_t GlobalsAndSubsequentPaddingSize = | 
| 456 RegisterArg64On32->setIsArg(); | 809 GlobalsSize + LocalsSlotsPaddingBytes; | 
| 457 RegisterArg64On32->getLo()->setRegNum(RegLo); | 810 | 
| 458 RegisterArg64On32->getHi()->setRegNum(RegHi); | 811 if (MaybeLeafFunc) | 
| 459 Arg->setIsArg(false); | 812 MaxOutArgsSizeBytes = 0; | 
| 460 Args[I] = RegisterArg64On32; | 813 | 
| 461 Context.insert<InstAssign>(Arg, RegisterArg); | 814 // Adds the out args space to the stack, and align SP if necessary. | 
| 815 uint32_t TotalStackSizeBytes = PreservedRegsSizeBytes + SpillAreaSizeBytes; | |
| 816 | |
| 817 // TODO(sagar.thakur): Combine fixed alloca and maximum out argument size with | |
| 818 // TotalStackSizeBytes once lowerAlloca is implemented and leaf function | |
| 819 // information is generated by lowerCall. | |
| 820 | |
| 821 // Generate "addiu sp, sp, -TotalStackSizeBytes" | |
| 822 if (TotalStackSizeBytes) { | |
| 823 // Use the scratch register if needed to legalize the immediate. | |
| 824 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); | |
| 825 _addiu(SP, SP, -(TotalStackSizeBytes)); | |
| 826 } | |
| 827 | |
| 828 Ctx->statsUpdateFrameBytes(TotalStackSizeBytes); | |
| 829 | |
| 830 if (!PreservedGPRs.empty()) { | |
| 831 uint32_t StackOffset = TotalStackSizeBytes; | |
| 832 for (Variable *Var : *PreservedRegsInClass) { | |
| 833 Variable *PhysicalRegister = getPhysicalRegister(Var->getRegNum()); | |
| 834 StackOffset -= typeWidthInBytesOnStack(PhysicalRegister->getType()); | |
| 835 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); | |
| 836 OperandMIPS32Mem *MemoryLocation = OperandMIPS32Mem::create( | |
| 837 Func, IceType_i32, SP, | |
| 838 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackOffset))); | |
| 839 _sw(PhysicalRegister, MemoryLocation); | |
| 840 } | |
| 841 } | |
| 842 | |
| 843 Variable *FP = getPhysicalRegister(RegMIPS32::Reg_FP); | |
| 844 | |
| 845 // Generate "mov FP, SP" if needed. | |
| 846 if (UsesFramePointer) { | |
| 847 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); | |
| 848 _mov(FP, SP); | |
| 849 // Keep FP live for late-stage liveness analysis (e.g. asm-verbose mode). | |
| 850 Context.insert<InstFakeUse>(FP); | |
| 851 } | |
| 852 | |
| 853 // Fill in stack offsets for stack args, and copy args into registers for | |
| 854 // those that were register-allocated. Args are pushed right to left, so | |
| 855 // Arg[0] is closest to the stack/frame pointer. | |
| 856 const VarList &Args = Func->getArgs(); | |
| 857 size_t InArgsSizeBytes = 0; | |
| 858 TargetMIPS32::CallingConv CC; | |
| 859 uint32_t ArgNo = 0; | |
| 860 | |
| 861 for (Variable *Arg : Args) { | |
| 862 RegNumT DummyReg; | |
| 863 const Type Ty = Arg->getType(); | |
| 864 // Skip arguments passed in registers. | |
| 865 if (CC.argInReg(Ty, ArgNo, &DummyReg)) { | |
| 866 ArgNo++; | |
| 462 continue; | 867 continue; | 
| 463 } else { | 868 } else { | 
| 464 assert(Ty == IceType_i32); | 869 finishArgumentLowering(Arg, FP, TotalStackSizeBytes, &InArgsSizeBytes); | 
| 465 if (NumGPRRegsUsed >= MIPS32_MAX_GPR_ARG) | 870 } | 
| 466 continue; | 871 } | 
| 467 const auto RegNum = RegNumT::fixme(RegMIPS32::Reg_A0 + NumGPRRegsUsed); | 872 | 
| 468 ++NumGPRRegsUsed; | 873 // Fill in stack offsets for locals. | 
| 469 Variable *RegisterArg = Func->makeVariable(Ty); | 874 assignVarStackSlots(SortedSpilledVariables, SpillAreaPaddingBytes, | 
| 470 if (BuildDefs::dump()) { | 875 SpillAreaSizeBytes, GlobalsAndSubsequentPaddingSize, | 
| 471 RegisterArg->setName(Func, "home_reg:" + Arg->getName()); | 876 UsesFramePointer); | 
| 472 } | 877 this->HasComputedFrame = true; | 
| 473 RegisterArg->setRegNum(RegNum); | 878 | 
| 474 RegisterArg->setIsArg(); | 879 if (BuildDefs::dump() && Func->isVerbose(IceV_Frame)) { | 
| 475 Arg->setIsArg(false); | 880 OstreamLocker _(Func->getContext()); | 
| 476 Args[I] = RegisterArg; | 881 Ostream &Str = Func->getContext()->getStrDump(); | 
| 477 Context.insert<InstAssign>(Arg, RegisterArg); | 882 | 
| 478 } | 883 Str << "Stack layout:\n"; | 
| 479 } | 884 uint32_t SPAdjustmentPaddingSize = | 
| 480 } | 885 SpillAreaSizeBytes - LocalsSpillAreaSize - | 
| 481 | 886 GlobalsAndSubsequentPaddingSize - SpillAreaPaddingBytes - | 
| 482 Type TargetMIPS32::stackSlotType() { return IceType_i32; } | 887 MaxOutArgsSizeBytes; | 
| 483 | 888 Str << " in-args = " << InArgsSizeBytes << " bytes\n" | 
| 484 void TargetMIPS32::addProlog(CfgNode *Node) { | 889 << " preserved registers = " << PreservedRegsSizeBytes << " bytes\n" | 
| 485 (void)Node; | 890 << " spill area padding = " << SpillAreaPaddingBytes << " bytes\n" | 
| 891 << " globals spill area = " << GlobalsSize << " bytes\n" | |
| 892 << " globals-locals spill areas intermediate padding = " | |
| 893 << GlobalsAndSubsequentPaddingSize - GlobalsSize << " bytes\n" | |
| 894 << " locals spill area = " << LocalsSpillAreaSize << " bytes\n" | |
| 895 << " SP alignment padding = " << SPAdjustmentPaddingSize << " bytes\n"; | |
| 896 | |
| 897 Str << "Stack details:\n" | |
| 898 << " SP adjustment = " << SpillAreaSizeBytes << " bytes\n" | |
| 899 << " spill area alignment = " << SpillAreaAlignmentBytes << " bytes\n" | |
| 900 << " outgoing args size = " << MaxOutArgsSizeBytes << " bytes\n" | |
| 901 << " locals spill area alignment = " << LocalsSlotsAlignmentBytes | |
| 902 << " bytes\n" | |
| 903 << " is FP based = " << 1 << "\n"; | |
| 904 } | |
| 486 return; | 905 return; | 
| 487 UnimplementedError(getFlags()); | |
| 488 } | 906 } | 
| 489 | 907 | 
| 490 void TargetMIPS32::addEpilog(CfgNode *Node) { | 908 void TargetMIPS32::addEpilog(CfgNode *Node) { | 
| 491 (void)Node; | 909 (void)Node; | 
| 492 return; | 910 return; | 
| 493 UnimplementedError(getFlags()); | 911 UnimplementedError(getFlags()); | 
| 494 } | 912 } | 
| 495 | 913 | 
| 496 Operand *TargetMIPS32::loOperand(Operand *Operand) { | 914 Operand *TargetMIPS32::loOperand(Operand *Operand) { | 
| 497 assert(Operand->getType() == IceType_i64); | 915 assert(Operand->getType() == IceType_i64); | 
| (...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 700 Operand *Src0 = legalizeUndef(Instr->getSrc(0)); | 1118 Operand *Src0 = legalizeUndef(Instr->getSrc(0)); | 
| 701 Operand *Src1 = legalizeUndef(Instr->getSrc(1)); | 1119 Operand *Src1 = legalizeUndef(Instr->getSrc(1)); | 
| 702 if (DestTy == IceType_i64) { | 1120 if (DestTy == IceType_i64) { | 
| 703 lowerInt64Arithmetic(Instr, Instr->getDest(), Src0, Src1); | 1121 lowerInt64Arithmetic(Instr, Instr->getDest(), Src0, Src1); | 
| 704 return; | 1122 return; | 
| 705 } | 1123 } | 
| 706 if (isVectorType(Dest->getType())) { | 1124 if (isVectorType(Dest->getType())) { | 
| 707 UnimplementedLoweringError(this, Instr); | 1125 UnimplementedLoweringError(this, Instr); | 
| 708 return; | 1126 return; | 
| 709 } | 1127 } | 
| 710 switch (Instr->getOp()) { | |
| 711 default: | |
| 712 break; | |
| 713 case InstArithmetic::Fadd: | |
| 714 case InstArithmetic::Fsub: | |
| 715 case InstArithmetic::Fmul: | |
| 716 case InstArithmetic::Fdiv: | |
| 717 case InstArithmetic::Frem: | |
| 718 UnimplementedLoweringError(this, Instr); | |
| 719 return; | |
| 720 } | |
| 721 | 1128 | 
| 722 // At this point Dest->getType() is non-i64 scalar | 1129 // At this point Dest->getType() is non-i64 scalar | 
| 723 | 1130 | 
| 724 Variable *T = makeReg(Dest->getType()); | 1131 Variable *T = makeReg(Dest->getType()); | 
| 725 Variable *Src0R = legalizeToReg(Src0); | 1132 Variable *Src0R = legalizeToReg(Src0); | 
| 726 Variable *Src1R = legalizeToReg(Src1); | 1133 Variable *Src1R = legalizeToReg(Src1); | 
| 727 | 1134 | 
| 728 switch (Instr->getOp()) { | 1135 switch (Instr->getOp()) { | 
| 729 case InstArithmetic::_num: | 1136 case InstArithmetic::_num: | 
| 730 break; | 1137 break; | 
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 789 _mov(Dest, T); | 1196 _mov(Dest, T); | 
| 790 return; | 1197 return; | 
| 791 } | 1198 } | 
| 792 case InstArithmetic::Srem: { | 1199 case InstArithmetic::Srem: { | 
| 793 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO); | 1200 auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO); | 
| 794 _div(T_Zero, Src0R, Src1R); | 1201 _div(T_Zero, Src0R, Src1R); | 
| 795 _mfhi(T, T_Zero); | 1202 _mfhi(T, T_Zero); | 
| 796 _mov(Dest, T); | 1203 _mov(Dest, T); | 
| 797 return; | 1204 return; | 
| 798 } | 1205 } | 
| 799 case InstArithmetic::Fadd: | 1206 case InstArithmetic::Fadd: { | 
| 1207 if (DestTy == IceType_f32) { | |
| 1208 _add_s(T, Src0R, Src1R); | |
| 1209 _mov_s(Dest, T); | |
| 
Jim Stichnoth
2016/06/13 20:14:19
From this, I am seeing invalid asm code being gene
 | |
| 1210 return; | |
| 1211 } | |
| 1212 if (DestTy == IceType_f64) { | |
| 1213 _add_d(T, Src0R, Src1R); | |
| 1214 _mov_d(Dest, T); | |
| 1215 return; | |
| 1216 } | |
| 800 break; | 1217 break; | 
| 1218 } | |
| 801 case InstArithmetic::Fsub: | 1219 case InstArithmetic::Fsub: | 
| 1220 if (DestTy == IceType_f32) { | |
| 1221 _sub_s(T, Src0R, Src1R); | |
| 1222 _mov_s(Dest, T); | |
| 1223 return; | |
| 1224 } | |
| 1225 if (DestTy == IceType_f64) { | |
| 1226 _sub_d(T, Src0R, Src1R); | |
| 1227 _mov_d(Dest, T); | |
| 1228 return; | |
| 1229 } | |
| 802 break; | 1230 break; | 
| 803 case InstArithmetic::Fmul: | 1231 case InstArithmetic::Fmul: | 
| 1232 if (DestTy == IceType_f32) { | |
| 1233 _mul_s(T, Src0R, Src1R); | |
| 1234 _mov_s(Dest, T); | |
| 1235 return; | |
| 1236 } | |
| 1237 if (DestTy == IceType_f64) { | |
| 1238 _mul_d(T, Src0R, Src1R); | |
| 1239 _mov_d(Dest, T); | |
| 1240 return; | |
| 1241 } | |
| 804 break; | 1242 break; | 
| 805 case InstArithmetic::Fdiv: | 1243 case InstArithmetic::Fdiv: | 
| 1244 if (DestTy == IceType_f32) { | |
| 1245 _div_s(T, Src0R, Src1R); | |
| 1246 _mov_s(Dest, T); | |
| 1247 return; | |
| 1248 } | |
| 1249 if (DestTy == IceType_f64) { | |
| 1250 _div_d(T, Src0R, Src1R); | |
| 1251 _mov_d(Dest, T); | |
| 1252 return; | |
| 1253 } | |
| 806 break; | 1254 break; | 
| 807 case InstArithmetic::Frem: | 1255 case InstArithmetic::Frem: | 
| 
Jim Stichnoth
2016/06/13 20:14:19
For now, avoid a liveness validation error by addi
 | |
| 808 break; | 1256 break; | 
| 809 } | 1257 } | 
| 810 UnimplementedLoweringError(this, Instr); | 1258 UnimplementedLoweringError(this, Instr); | 
| 811 } | 1259 } | 
| 812 | 1260 | 
| 813 void TargetMIPS32::lowerAssign(const InstAssign *Instr) { | 1261 void TargetMIPS32::lowerAssign(const InstAssign *Instr) { | 
| 814 Variable *Dest = Instr->getDest(); | 1262 Variable *Dest = Instr->getDest(); | 
| 815 Operand *Src0 = Instr->getSrc(0); | 1263 Operand *Src0 = Instr->getSrc(0); | 
| 816 assert(Dest->getType() == Src0->getType()); | 1264 assert(Dest->getType() == Src0->getType()); | 
| 817 if (Dest->getType() == IceType_i64) { | 1265 if (Dest->getType() == IceType_i64) { | 
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 927 _slt(DestT, Src1R, Src0R); | 1375 _slt(DestT, Src1R, Src0R); | 
| 928 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 1376 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 
| 929 break; | 1377 break; | 
| 930 } | 1378 } | 
| 931 } | 1379 } | 
| 932 } | 1380 } | 
| 933 } | 1381 } | 
| 934 | 1382 | 
| 935 void TargetMIPS32::lowerCall(const InstCall *Instr) { | 1383 void TargetMIPS32::lowerCall(const InstCall *Instr) { | 
| 936 // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. | 1384 // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. | 
| 937 if (Instr->getNumArgs()) { | 1385 // if (Instr->getNumArgs()) { | 
| 
Jim Stichnoth
2016/06/13 20:14:19
remove this
 | |
| 938 UnimplementedLoweringError(this, Instr); | 1386 // UnimplementedLoweringError(this, Instr); | 
| 939 return; | 1387 // return; | 
| 940 } | 1388 //} | 
| 941 // Generate the call instruction. Assign its result to a temporary with high | 1389 // Generate the call instruction. Assign its result to a temporary with high | 
| 942 // register allocation weight. | 1390 // register allocation weight. | 
| 943 Variable *Dest = Instr->getDest(); | 1391 Variable *Dest = Instr->getDest(); | 
| 944 // ReturnReg doubles as ReturnRegLo as necessary. | 1392 // ReturnReg doubles as ReturnRegLo as necessary. | 
| 945 Variable *ReturnReg = nullptr; | 1393 Variable *ReturnReg = nullptr; | 
| 946 Variable *ReturnRegHi = nullptr; | 1394 Variable *ReturnRegHi = nullptr; | 
| 947 if (Dest) { | 1395 if (Dest) { | 
| 948 switch (Dest->getType()) { | 1396 switch (Dest->getType()) { | 
| 949 case IceType_NUM: | 1397 case IceType_NUM: | 
| 950 llvm_unreachable("Invalid Call dest type"); | 1398 llvm_unreachable("Invalid Call dest type"); | 
| 951 return; | 1399 return; | 
| 952 case IceType_void: | 1400 case IceType_void: | 
| 953 break; | 1401 break; | 
| 954 case IceType_i1: | 1402 case IceType_i1: | 
| 955 case IceType_i8: | 1403 case IceType_i8: | 
| 956 case IceType_i16: | 1404 case IceType_i16: | 
| 957 case IceType_i32: | 1405 case IceType_i32: | 
| 958 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0); | 1406 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_V0); | 
| 959 break; | 1407 break; | 
| 960 case IceType_i64: | 1408 case IceType_i64: | 
| 961 ReturnReg = I32Reg(RegMIPS32::Reg_V0); | 1409 ReturnReg = I32Reg(RegMIPS32::Reg_V0); | 
| 962 ReturnRegHi = I32Reg(RegMIPS32::Reg_V1); | 1410 ReturnRegHi = I32Reg(RegMIPS32::Reg_V1); | 
| 963 break; | 1411 break; | 
| 964 case IceType_f32: | 1412 case IceType_f32: | 
| 1413 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_F0); | |
| 1414 break; | |
| 965 case IceType_f64: | 1415 case IceType_f64: | 
| 966 UnimplementedLoweringError(this, Instr); | 1416 ReturnReg = makeReg(Dest->getType(), RegMIPS32::Reg_F0F1); | 
| 967 return; | 1417 break; | 
| 968 case IceType_v4i1: | 1418 case IceType_v4i1: | 
| 969 case IceType_v8i1: | 1419 case IceType_v8i1: | 
| 970 case IceType_v16i1: | 1420 case IceType_v16i1: | 
| 971 case IceType_v16i8: | 1421 case IceType_v16i8: | 
| 972 case IceType_v8i16: | 1422 case IceType_v8i16: | 
| 973 case IceType_v4i32: | 1423 case IceType_v4i32: | 
| 974 case IceType_v4f32: | 1424 case IceType_v4f32: { | 
| 975 UnimplementedLoweringError(this, Instr); | 1425 UnimplementedLoweringError(this, Instr); | 
| 976 return; | 1426 return; | 
| 977 } | 1427 } | 
| 1428 } | |
| 978 } | 1429 } | 
| 979 Operand *CallTarget = Instr->getCallTarget(); | 1430 Operand *CallTarget = Instr->getCallTarget(); | 
| 980 // Allow ConstantRelocatable to be left alone as a direct call, | 1431 // Allow ConstantRelocatable to be left alone as a direct call, | 
| 981 // but force other constants like ConstantInteger32 to be in | 1432 // but force other constants like ConstantInteger32 to be in | 
| 982 // a register and make it an indirect call. | 1433 // a register and make it an indirect call. | 
| 983 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 1434 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 
| 984 CallTarget = legalize(CallTarget, Legal_Reg); | 1435 CallTarget = legalize(CallTarget, Legal_Reg); | 
| 985 } | 1436 } | 
| 986 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); | 1437 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); | 
| 987 Context.insert(NewCall); | 1438 Context.insert(NewCall); | 
| 988 if (ReturnRegHi) | 1439 if (ReturnRegHi) | 
| 989 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 1440 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 
| 990 // Insert a register-kill pseudo instruction. | 1441 // Insert a register-kill pseudo instruction. | 
| 991 Context.insert(InstFakeKill::create(Func, NewCall)); | 1442 Context.insert(InstFakeKill::create(Func, NewCall)); | 
| 992 // Generate a FakeUse to keep the call live if necessary. | 1443 // Generate a FakeUse to keep the call live if necessary. | 
| 993 if (Instr->hasSideEffects() && ReturnReg) { | 1444 if (Instr->hasSideEffects() && ReturnReg) { | 
| 994 Context.insert<InstFakeDef>(ReturnReg); | 1445 Context.insert<InstFakeDef>(ReturnReg); | 
| 
Jim Stichnoth
2016/06/13 20:14:19
InstFakeUse
 | |
| 995 } | 1446 } | 
| 996 if (Dest == nullptr) | 1447 if (Dest == nullptr) | 
| 997 return; | 1448 return; | 
| 998 | 1449 | 
| 999 // Assign the result of the call to Dest. | 1450 // Assign the result of the call to Dest. | 
| 1000 if (ReturnReg) { | 1451 if (ReturnReg) { | 
| 1001 if (ReturnRegHi) { | 1452 auto *Zero = getZero(); | 
| 1002 assert(Dest->getType() == IceType_i64); | 1453 switch (Dest->getType()) { | 
| 1454 default: | |
| 1455 UnimplementedLoweringError(this, Instr); | |
| 1456 case IceType_i1: | |
| 1457 case IceType_i8: | |
| 1458 case IceType_i16: | |
| 1459 case IceType_i32: { | |
| 1460 _addu(Dest, Zero, ReturnReg); | |
| 1461 break; | |
| 1462 } | |
| 1463 case IceType_i64: { | |
| 1003 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); | 1464 auto *Dest64On32 = llvm::cast<Variable64On32>(Dest); | 
| 1004 Variable *DestLo = Dest64On32->getLo(); | 1465 Variable *DestLo = Dest64On32->getLo(); | 
| 1005 Variable *DestHi = Dest64On32->getHi(); | 1466 Variable *DestHi = Dest64On32->getHi(); | 
| 1006 _mov(DestLo, ReturnReg); | 1467 _addu(DestLo, Zero, ReturnReg); | 
| 1007 _mov(DestHi, ReturnRegHi); | 1468 _addu(DestHi, Zero, ReturnRegHi); | 
| 1008 } else { | 1469 break; | 
| 1009 assert(Dest->getType() == IceType_i32 || Dest->getType() == IceType_i16 || | 1470 } | 
| 1010 Dest->getType() == IceType_i8 || Dest->getType() == IceType_i1 || | 1471 case IceType_f32: { | 
| 1011 isVectorType(Dest->getType())); | 1472 _mov_s(Dest, ReturnReg); | 
| 1012 if (isFloatingType(Dest->getType()) || isVectorType(Dest->getType())) { | 1473 break; | 
| 1013 UnimplementedLoweringError(this, Instr); | 1474 } | 
| 1014 return; | 1475 case IceType_f64: { | 
| 1015 } else { | 1476 _mov_d(Dest, ReturnReg); | 
| 1016 _mov(Dest, ReturnReg); | 1477 break; | 
| 1017 } | 1478 } | 
| 1479 case IceType_v4i1: | |
| 1480 case IceType_v8i1: | |
| 1481 case IceType_v16i1: | |
| 1482 case IceType_v16i8: | |
| 1483 case IceType_v8i16: | |
| 1484 case IceType_v4i32: | |
| 1485 case IceType_v4f32: { | |
| 1486 UnimplementedLoweringError(this, Instr); | |
| 1487 return; | |
| 1488 } | |
| 1018 } | 1489 } | 
| 1019 } | 1490 } | 
| 1020 } | 1491 } | 
| 1021 | 1492 | 
| 1022 void TargetMIPS32::lowerCast(const InstCast *Instr) { | 1493 void TargetMIPS32::lowerCast(const InstCast *Instr) { | 
| 1023 InstCast::OpKind CastKind = Instr->getCastKind(); | 1494 InstCast::OpKind CastKind = Instr->getCastKind(); | 
| 1024 Variable *Dest = Instr->getDest(); | 1495 Variable *Dest = Instr->getDest(); | 
| 1025 Operand *Src0 = legalizeUndef(Instr->getSrc(0)); | 1496 Operand *Src0 = legalizeUndef(Instr->getSrc(0)); | 
| 1026 const Type DestTy = Dest->getType(); | 1497 const Type DestTy = Dest->getType(); | 
| 1027 const Type Src0Ty = Src0->getType(); | 1498 const Type Src0Ty = Src0->getType(); | 
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1416 } | 1887 } | 
| 1417 | 1888 | 
| 1418 void TargetMIPS32::lowerPhi(const InstPhi * /*Instr*/) { | 1889 void TargetMIPS32::lowerPhi(const InstPhi * /*Instr*/) { | 
| 1419 Func->setError("Phi found in regular instruction list"); | 1890 Func->setError("Phi found in regular instruction list"); | 
| 1420 } | 1891 } | 
| 1421 | 1892 | 
| 1422 void TargetMIPS32::lowerRet(const InstRet *Instr) { | 1893 void TargetMIPS32::lowerRet(const InstRet *Instr) { | 
| 1423 Variable *Reg = nullptr; | 1894 Variable *Reg = nullptr; | 
| 1424 if (Instr->hasRetValue()) { | 1895 if (Instr->hasRetValue()) { | 
| 1425 Operand *Src0 = Instr->getRetValue(); | 1896 Operand *Src0 = Instr->getRetValue(); | 
| 1897 | |
| 1426 switch (Src0->getType()) { | 1898 switch (Src0->getType()) { | 
| 1899 default: | |
| 1900 UnimplementedLoweringError(this, Instr); | |
| 
Jim Stichnoth
2016/06/13 20:14:19
You probably want a "break;" after this, otherwise
 | |
| 1901 case IceType_f32: { | |
| 1902 if (auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { | |
| 1903 Reg = makeReg(Src0V->getType(), RegMIPS32::Reg_F0); | |
| 1904 _mov_s(Reg, Src0V); | |
| 1905 } | |
| 1906 break; | |
| 1907 } | |
| 1908 case IceType_f64: { | |
| 1909 if (auto *Src0V = llvm::dyn_cast<Variable>(Src0)) { | |
| 1910 Reg = makeReg(Src0V->getType(), RegMIPS32::Reg_F0F1); | |
| 1911 _mov_d(Reg, Src0V); | |
| 1912 } | |
| 1913 break; | |
| 1914 } | |
| 1427 case IceType_i1: | 1915 case IceType_i1: | 
| 1428 case IceType_i8: | 1916 case IceType_i8: | 
| 1429 case IceType_i16: | 1917 case IceType_i16: | 
| 1430 case IceType_i32: { | 1918 case IceType_i32: { | 
| 1431 // Reg = legalizeToReg(Src0, RegMIPS32::Reg_V0); | 1919 // Reg = legalizeToReg(Src0, RegMIPS32::Reg_V0); | 
| 1432 Operand *Src0F = legalize(Src0, Legal_Reg); | 1920 Operand *Src0F = legalize(Src0, Legal_Reg); | 
| 1433 Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_V0); | 1921 Reg = makeReg(Src0F->getType(), RegMIPS32::Reg_V0); | 
| 1434 _mov(Reg, Src0F); | 1922 _mov(Reg, Src0F); | 
| 1435 break; | 1923 break; | 
| 1436 } | 1924 } | 
| 1437 case IceType_i64: { | 1925 case IceType_i64: { | 
| 1438 Src0 = legalizeUndef(Src0); | 1926 Src0 = legalizeUndef(Src0); | 
| 1439 Variable *R0 = legalizeToReg(loOperand(Src0), RegMIPS32::Reg_V0); | 1927 Variable *R0 = legalizeToReg(loOperand(Src0), RegMIPS32::Reg_V0); | 
| 1440 Variable *R1 = legalizeToReg(hiOperand(Src0), RegMIPS32::Reg_V1); | 1928 Variable *R1 = legalizeToReg(hiOperand(Src0), RegMIPS32::Reg_V1); | 
| 1441 Reg = R0; | 1929 Reg = R0; | 
| 1442 Context.insert<InstFakeUse>(R1); | 1930 Context.insert<InstFakeUse>(R1); | 
| 1443 break; | 1931 break; | 
| 1444 } | 1932 } | 
| 1445 | 1933 case IceType_v4i1: | 
| 1446 default: | 1934 case IceType_v8i1: | 
| 1935 case IceType_v16i1: | |
| 1936 case IceType_v16i8: | |
| 1937 case IceType_v8i16: | |
| 1938 case IceType_v4i32: | |
| 1939 case IceType_v4f32: { | |
| 1447 UnimplementedLoweringError(this, Instr); | 1940 UnimplementedLoweringError(this, Instr); | 
| 1941 break; | |
| 1942 } | |
| 1448 } | 1943 } | 
| 1449 } | 1944 } | 
| 1450 _ret(getPhysicalRegister(RegMIPS32::Reg_RA), Reg); | 1945 _ret(getPhysicalRegister(RegMIPS32::Reg_RA), Reg); | 
| 1451 } | 1946 } | 
| 1452 | 1947 | 
| 1453 void TargetMIPS32::lowerSelect(const InstSelect *Instr) { | 1948 void TargetMIPS32::lowerSelect(const InstSelect *Instr) { | 
| 1454 UnimplementedLoweringError(this, Instr); | 1949 UnimplementedLoweringError(this, Instr); | 
| 1455 } | 1950 } | 
| 1456 | 1951 | 
| 1457 void TargetMIPS32::lowerShuffleVector(const InstShuffleVector *Instr) { | 1952 void TargetMIPS32::lowerShuffleVector(const InstShuffleVector *Instr) { | 
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1544 emitGlobal(*Var, SectionSuffix); | 2039 emitGlobal(*Var, SectionSuffix); | 
| 1545 } | 2040 } | 
| 1546 } | 2041 } | 
| 1547 } break; | 2042 } break; | 
| 1548 } | 2043 } | 
| 1549 } | 2044 } | 
| 1550 | 2045 | 
| 1551 void TargetDataMIPS32::lowerConstants() { | 2046 void TargetDataMIPS32::lowerConstants() { | 
| 1552 if (getFlags().getDisableTranslation()) | 2047 if (getFlags().getDisableTranslation()) | 
| 1553 return; | 2048 return; | 
| 1554 UnimplementedError(getFlags()); | 2049 // UnimplementedError(getFlags()); | 
| 
Jim Stichnoth
2016/06/13 20:14:19
remove this
 | |
| 1555 } | 2050 } | 
| 1556 | 2051 | 
| 1557 void TargetDataMIPS32::lowerJumpTables() { | 2052 void TargetDataMIPS32::lowerJumpTables() { | 
| 1558 if (getFlags().getDisableTranslation()) | 2053 if (getFlags().getDisableTranslation()) | 
| 1559 return; | 2054 return; | 
| 1560 UnimplementedError(getFlags()); | 2055 // UnimplementedError(getFlags()); | 
| 
Jim Stichnoth
2016/06/13 20:14:19
remove this
 | |
| 1561 } | 2056 } | 
| 1562 | 2057 | 
| 1563 // Helper for legalize() to emit the right code to lower an operand to a | 2058 // Helper for legalize() to emit the right code to lower an operand to a | 
| 1564 // register of the appropriate type. | 2059 // register of the appropriate type. | 
| 1565 Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) { | 2060 Variable *TargetMIPS32::copyToReg(Operand *Src, RegNumT RegNum) { | 
| 1566 Type Ty = Src->getType(); | 2061 Type Ty = Src->getType(); | 
| 1567 Variable *Reg = makeReg(Ty, RegNum); | 2062 Variable *Reg = makeReg(Ty, RegNum); | 
| 1568 if (isVectorType(Ty) || isFloatingType(Ty)) { | 2063 if (isVectorType(Ty)) { | 
| 1569 UnimplementedError(getFlags()); | 2064 UnimplementedError(getFlags()); | 
| 2065 } else if (isFloatingType(Ty)) { | |
| 2066 (Ty == IceType_f32) ? _mov_s(Reg, llvm::dyn_cast<Variable>(Src)) | |
| 2067 : _mov_d(Reg, llvm::dyn_cast<Variable>(Src)); | |
| 1570 } else { | 2068 } else { | 
| 1571 // Mov's Src operand can really only be the flexible second operand type | 2069 // Mov's Src operand can really only be the flexible second operand type | 
| 1572 // or a register. Users should guarantee that. | 2070 // or a register. Users should guarantee that. | 
| 1573 _mov(Reg, Src); | 2071 _mov(Reg, Src); | 
| 1574 } | 2072 } | 
| 1575 return Reg; | 2073 return Reg; | 
| 1576 } | 2074 } | 
| 1577 | 2075 | 
| 1578 Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, | 2076 Operand *TargetMIPS32::legalize(Operand *From, LegalMask Allowed, | 
| 1579 RegNumT RegNum) { | 2077 RegNumT RegNum) { | 
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1714 Str << "\t.set\t" | 2212 Str << "\t.set\t" | 
| 1715 << "nomips16\n"; | 2213 << "nomips16\n"; | 
| 1716 } | 2214 } | 
| 1717 | 2215 | 
| 1718 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 2216 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 
| 1719 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 2217 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 
| 1720 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 2218 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 
| 1721 | 2219 | 
| 1722 } // end of namespace MIPS32 | 2220 } // end of namespace MIPS32 | 
| 1723 } // end of namespace Ice | 2221 } // end of namespace Ice | 
| OLD | NEW |