Chromium Code Reviews| 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 | |
| 67 const char *getRegClassName(RegClass C) { | 70 const char *getRegClassName(RegClass C) { |
| 68 auto ClassNum = static_cast<RegClassMIPS32>(C); | 71 auto ClassNum = static_cast<RegClassMIPS32>(C); |
| 69 assert(ClassNum < RCMIPS32_NUM); | 72 assert(ClassNum < RCMIPS32_NUM); |
| 70 switch (ClassNum) { | 73 switch (ClassNum) { |
| 71 default: | 74 default: |
| 72 assert(C < RC_Target); | 75 assert(C < RC_Target); |
| 73 return regClassString(C); | 76 return regClassString(C); |
| 74 // Add handling of new register classes below. | 77 // Add handling of new register classes below. |
| 75 } | 78 } |
| 76 } | 79 } |
| 77 | 80 |
| 81 // Stack alignment | |
| 82 const uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16; | |
|
Jim Stichnoth
2016/05/31 16:37:45
Can this be constexpr?
| |
| 83 | |
| 84 // Value is in bytes. Return Value adjusted to the next highest multiple of the | |
| 85 // stack alignment. | |
| 86 uint32_t applyStackAlignment(uint32_t Value) { | |
| 87 return Utils::applyAlignment(Value, MIPS32_STACK_ALIGNMENT_BYTES); | |
| 88 } | |
| 89 | |
| 90 // Value is in bytes. Return Value adjusted to the next highest multiple of the | |
| 91 // stack alignment required for the given type. | |
| 92 uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { | |
| 93 size_t typeAlignInBytes = typeWidthInBytes(Ty); | |
| 94 if (isVectorType(Ty)) | |
| 95 typeAlignInBytes = 8; | |
| 96 return Utils::applyAlignment(Value, typeAlignInBytes); | |
| 97 } | |
| 98 | |
| 78 } // end of anonymous namespace | 99 } // end of anonymous namespace |
| 79 | 100 |
| 80 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} | 101 TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} |
| 81 | 102 |
| 82 void TargetMIPS32::staticInit(GlobalContext *Ctx) { | 103 void TargetMIPS32::staticInit(GlobalContext *Ctx) { |
| 83 (void)Ctx; | 104 (void)Ctx; |
| 84 RegNumT::setLimit(RegMIPS32::Reg_NUM); | 105 RegNumT::setLimit(RegMIPS32::Reg_NUM); |
| 85 SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM); | 106 SmallBitVector IntegerRegisters(RegMIPS32::Reg_NUM); |
| 86 SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM); | 107 SmallBitVector I64PairRegisters(RegMIPS32::Reg_NUM); |
| 87 SmallBitVector Float32Registers(RegMIPS32::Reg_NUM); | 108 SmallBitVector Float32Registers(RegMIPS32::Reg_NUM); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 98 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 119 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ |
| 99 for (SizeT RegAlias : alias_init) { \ | 120 for (SizeT RegAlias : alias_init) { \ |
| 100 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ | 121 assert(!RegisterAliases[RegMIPS32::val][RegAlias] && \ |
| 101 "Duplicate alias for " #val); \ | 122 "Duplicate alias for " #val); \ |
| 102 RegisterAliases[RegMIPS32::val].set(RegAlias); \ | 123 RegisterAliases[RegMIPS32::val].set(RegAlias); \ |
| 103 } \ | 124 } \ |
| 104 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ | 125 RegisterAliases[RegMIPS32::val].resize(RegMIPS32::Reg_NUM); \ |
| 105 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); | 126 assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); |
| 106 REGMIPS32_TABLE; | 127 REGMIPS32_TABLE; |
| 107 #undef X | 128 #undef X |
| 129 | |
| 130 for(size_t i = 0; i<MIPS32_MAX_GPR_ARG ; i++) | |
| 131 GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i); | |
|
Jim Stichnoth
2016/05/31 16:37:45
This CL introduces several new uses of fixme(), wh
| |
| 132 | |
| 133 for(size_t i = 0; i<MIPS32_MAX_GPR_ARG/2 ; i++) | |
| 134 I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i); | |
| 135 | |
| 108 TypeToRegisterSet[IceType_void] = InvalidRegisters; | 136 TypeToRegisterSet[IceType_void] = InvalidRegisters; |
| 109 TypeToRegisterSet[IceType_i1] = IntegerRegisters; | 137 TypeToRegisterSet[IceType_i1] = IntegerRegisters; |
| 110 TypeToRegisterSet[IceType_i8] = IntegerRegisters; | 138 TypeToRegisterSet[IceType_i8] = IntegerRegisters; |
| 111 TypeToRegisterSet[IceType_i16] = IntegerRegisters; | 139 TypeToRegisterSet[IceType_i16] = IntegerRegisters; |
| 112 TypeToRegisterSet[IceType_i32] = IntegerRegisters; | 140 TypeToRegisterSet[IceType_i32] = IntegerRegisters; |
| 113 TypeToRegisterSet[IceType_i64] = IntegerRegisters; | 141 TypeToRegisterSet[IceType_i64] = IntegerRegisters; |
| 114 TypeToRegisterSet[IceType_f32] = Float32Registers; | 142 TypeToRegisterSet[IceType_f32] = Float32Registers; |
| 115 TypeToRegisterSet[IceType_f64] = Float64Registers; | 143 TypeToRegisterSet[IceType_f64] = Float64Registers; |
| 116 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; | 144 TypeToRegisterSet[IceType_v4i1] = VectorRegisters; |
| 117 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; | 145 TypeToRegisterSet[IceType_v8i1] = VectorRegisters; |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 382 return; | 410 return; |
| 383 } else { | 411 } else { |
| 384 int32_t Offset = Var->getStackOffset(); | 412 int32_t Offset = Var->getStackOffset(); |
| 385 Str << Offset; | 413 Str << Offset; |
| 386 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); | 414 Str << "($" << getRegName(getFrameOrStackReg(), FrameSPTy); |
| 387 Str << ")"; | 415 Str << ")"; |
| 388 } | 416 } |
| 389 UnimplementedError(getFlags()); | 417 UnimplementedError(getFlags()); |
| 390 } | 418 } |
| 391 | 419 |
| 420 TargetMIPS32::CallingConv::CallingConv() | |
| 421 : GPRegsUsed(RegMIPS32::Reg_NUM), | |
| 422 GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()), | |
| 423 I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()) {} | |
| 424 | |
| 425 bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) { | |
| 426 CfgVector<RegNumT> *Source; | |
| 427 | |
| 428 switch (Ty) { | |
| 429 default: { | |
| 430 assert(isScalarIntegerType(Ty)); | |
| 431 Source = &GPRArgs; | |
| 432 } break; | |
| 433 case IceType_i64: { | |
| 434 Source = &I64Args; | |
| 435 } break; | |
| 436 } | |
| 437 | |
| 438 discardUnavailableGPRsAndTheirAliases(Source); | |
| 439 | |
| 440 if (Source->empty()) { | |
| 441 GPRegsUsed.set(); | |
| 442 return false; | |
| 443 } | |
| 444 | |
| 445 *Reg = Source->back(); | |
| 446 // Note that we don't Source->pop_back() here. This is intentional. Notice how | |
| 447 // we mark all of Reg's aliases as Used. So, for the next argument, | |
| 448 // Source->back() is marked as unavailable, and it is thus implicitly popped | |
| 449 // from the stack. | |
| 450 GPRegsUsed |= RegisterAliases[*Reg]; | |
| 451 return true; | |
| 452 } | |
| 453 | |
| 454 // GPR are not packed when passing parameters. Thus, a function foo(i32, i64, | |
| 455 // i32) will have the first argument in r0, the second in r2-r3, and the third | |
| 456 // on the stack. To model this behavior, whenever we pop a register from Regs, | |
| 457 // we remove all of its aliases from the pool of available GPRs. This has the | |
| 458 // effect of computing the "closure" on the GPR registers. | |
| 459 void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases( | |
| 460 CfgVector<RegNumT> *Regs) { | |
| 461 while (!Regs->empty() && GPRegsUsed[Regs->back()]) { | |
| 462 GPRegsUsed |= RegisterAliases[Regs->back()]; | |
| 463 Regs->pop_back(); | |
| 464 } | |
| 465 } | |
| 466 | |
| 392 void TargetMIPS32::lowerArguments() { | 467 void TargetMIPS32::lowerArguments() { |
| 393 VarList &Args = Func->getArgs(); | 468 VarList &Args = Func->getArgs(); |
| 394 // We are only handling integer registers for now. The Mips o32 ABI is | 469 // We are only handling integer registers for now. The Mips o32 ABI is |
| 395 // somewhat complex but will be implemented in its totality through follow | 470 // somewhat complex but will be implemented in its totality through follow |
| 396 // on patches. | 471 // on patches. |
| 397 // | 472 // |
| 398 unsigned NumGPRRegsUsed = 0; | 473 unsigned NumGPRRegsUsed = 0; |
| 399 // For each register argument, replace Arg in the argument list with the | 474 // For each register argument, replace Arg in the argument list with the |
| 400 // home register. Then generate an instruction in the prolog to copy the | 475 // home register. Then generate an instruction in the prolog to copy the |
| 401 // home register to the assigned location of Arg. | 476 // home register to the assigned location of Arg. |
| (...skipping 507 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 909 case InstIcmp::Sle: { | 984 case InstIcmp::Sle: { |
| 910 _slt(DestT, Src1R, Src0R); | 985 _slt(DestT, Src1R, Src0R); |
| 911 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); | 986 _br(TargetTrue, TargetFalse, DestT, CondMIPS32::Cond::NEZ); |
| 912 break; | 987 break; |
| 913 } | 988 } |
| 914 } | 989 } |
| 915 } | 990 } |
| 916 } | 991 } |
| 917 | 992 |
| 918 void TargetMIPS32::lowerCall(const InstCall *Instr) { | 993 void TargetMIPS32::lowerCall(const InstCall *Instr) { |
| 919 // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. | 994 NeedsStackAlignment = true; |
| 920 if (Instr->getNumArgs()) { | 995 |
| 921 UnimplementedLoweringError(this, Instr); | 996 // Assign arguments to registers and stack. Also reserve stack. |
| 922 return; | 997 TargetMIPS32::CallingConv CC; |
| 998 | |
| 999 // Pair of Arg Operand -> GPR number assignments. | |
| 1000 llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_GPR_ARG> GPRArgs; | |
| 1001 | |
| 1002 // Pair of Arg Operand -> stack offset. | |
| 1003 llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs; | |
| 1004 size_t ParameterAreaSizeBytes = 16; | |
| 1005 | |
| 1006 // Classify each argument operand according to the location where the | |
| 1007 // argument is passed. | |
| 1008 | |
| 1009 for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) { | |
| 1010 Operand *Arg = legalizeUndef(Instr->getArg(i)); | |
| 1011 const Type Ty = Arg->getType(); | |
| 1012 bool InReg = false; | |
| 1013 RegNumT Reg; | |
| 1014 if (isScalarIntegerType(Ty)) { | |
| 1015 InReg = CC.argInGPR(Ty, &Reg); | |
| 1016 } else { | |
| 1017 // TODO(mohit.bhakkad) : Handle arguments of type other than ScalarInteger Type | |
|
Jim Stichnoth
2016/05/31 16:37:45
80-col, and pay special attention that "make forma
| |
| 1018 UnimplementedLoweringError(this, Instr); | |
| 1019 return; | |
| 1020 } | |
| 1021 | |
| 1022 if (!InReg) { | |
| 1023 ParameterAreaSizeBytes = | |
| 1024 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty); | |
| 1025 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes)); | |
| 1026 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty); | |
| 1027 continue; | |
| 1028 } | |
| 1029 | |
| 1030 if (Ty == IceType_i64) { | |
| 1031 Operand *Lo = loOperand(Arg); | |
| 1032 Operand *Hi = hiOperand(Arg); | |
| 1033 GPRArgs.push_back(std::make_pair( | |
| 1034 Lo, RegNumT::fixme(RegMIPS32::getI64PairFirstGPRNum(Reg)))); | |
|
Jim Stichnoth
2016/05/31 16:37:45
Can these two fixme() calls be removed?
| |
| 1035 GPRArgs.push_back(std::make_pair( | |
| 1036 Hi, RegNumT::fixme(RegMIPS32::getI64PairSecondGPRNum(Reg)))); | |
| 1037 } else if (isScalarIntegerType(Ty)) { | |
| 1038 GPRArgs.push_back(std::make_pair(Arg, Reg)); | |
| 1039 } else { | |
| 1040 // TODO(mohit.bhakkad) : Handle arguments of type other than ScalarInteger Type | |
| 1041 UnimplementedLoweringError(this, Instr); | |
| 1042 return; | |
| 1043 } | |
| 923 } | 1044 } |
| 1045 | |
| 1046 // Adjust the parameter area so that the stack is aligned. It is assumed that | |
| 1047 // the stack is already aligned at the start of the calling sequence. | |
| 1048 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes); | |
| 1049 | |
| 1050 // Copy arguments that are passed on the stack to the appropriate stack | |
| 1051 // locations. | |
| 1052 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); | |
| 1053 for (auto &StackArg : StackArgs) { | |
| 1054 ConstantInteger32 *Loc = | |
| 1055 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second)); | |
| 1056 Type Ty = StackArg.first->getType(); | |
| 1057 OperandMIPS32Mem *Addr; | |
| 1058 constexpr bool SignExt = false; | |
| 1059 if (OperandMIPS32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) { | |
| 1060 Addr = OperandMIPS32Mem::create(Func, Ty, SP, Loc); | |
| 1061 } else {// ignoring this part for now | |
| 1062 Variable *NewBase = Func->makeVariable(SP->getType()); | |
| 1063 lowerArithmetic( | |
| 1064 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc)); | |
| 1065 Addr = formMemoryOperand(NewBase, Ty); | |
| 1066 } | |
| 1067 lowerStore(InstStore::create(Func, StackArg.first, Addr)); | |
| 1068 } | |
| 1069 | |
| 924 // Generate the call instruction. Assign its result to a temporary with high | 1070 // Generate the call instruction. Assign its result to a temporary with high |
| 925 // register allocation weight. | 1071 // register allocation weight. |
| 926 Variable *Dest = Instr->getDest(); | 1072 Variable *Dest = Instr->getDest(); |
| 927 // ReturnReg doubles as ReturnRegLo as necessary. | 1073 // ReturnReg doubles as ReturnRegLo as necessary. |
| 928 Variable *ReturnReg = nullptr; | 1074 Variable *ReturnReg = nullptr; |
| 929 Variable *ReturnRegHi = nullptr; | 1075 Variable *ReturnRegHi = nullptr; |
| 930 if (Dest) { | 1076 if (Dest) { |
| 931 switch (Dest->getType()) { | 1077 switch (Dest->getType()) { |
| 932 case IceType_NUM: | 1078 case IceType_NUM: |
| 933 llvm_unreachable("Invalid Call dest type"); | 1079 llvm_unreachable("Invalid Call dest type"); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 959 return; | 1105 return; |
| 960 } | 1106 } |
| 961 } | 1107 } |
| 962 Operand *CallTarget = Instr->getCallTarget(); | 1108 Operand *CallTarget = Instr->getCallTarget(); |
| 963 // Allow ConstantRelocatable to be left alone as a direct call, | 1109 // Allow ConstantRelocatable to be left alone as a direct call, |
| 964 // but force other constants like ConstantInteger32 to be in | 1110 // but force other constants like ConstantInteger32 to be in |
| 965 // a register and make it an indirect call. | 1111 // a register and make it an indirect call. |
| 966 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 1112 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
| 967 CallTarget = legalize(CallTarget, Legal_Reg); | 1113 CallTarget = legalize(CallTarget, Legal_Reg); |
| 968 } | 1114 } |
| 1115 | |
| 1116 // Copy arguments to be passed in registers to the appropriate registers. | |
| 1117 CfgVector<Variable *> RegArgs; | |
| 1118 for (auto &GPRArg : GPRArgs) { | |
| 1119 RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second)); | |
| 1120 } | |
| 1121 | |
| 1122 // Generate a FakeUse of register arguments so that they do not get dead code | |
| 1123 // eliminated as a result of the FakeKill of scratch registers after the call. | |
| 1124 // These fake-uses need to be placed here to avoid argument registers from | |
| 1125 // being used during the legalizeToReg() calls above. | |
| 1126 for (auto *RegArg : RegArgs) { | |
| 1127 Context.insert<InstFakeUse>(RegArg); | |
| 1128 } | |
| 1129 | |
| 969 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); | 1130 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); |
| 970 Context.insert(NewCall); | 1131 Context.insert(NewCall); |
| 971 if (ReturnRegHi) | 1132 if (ReturnRegHi) |
| 972 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 1133 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); |
| 973 // Insert a register-kill pseudo instruction. | 1134 // Insert a register-kill pseudo instruction. |
| 974 Context.insert(InstFakeKill::create(Func, NewCall)); | 1135 Context.insert(InstFakeKill::create(Func, NewCall)); |
| 975 // Generate a FakeUse to keep the call live if necessary. | 1136 // Generate a FakeUse to keep the call live if necessary. |
| 976 if (Instr->hasSideEffects() && ReturnReg) { | 1137 if (Instr->hasSideEffects() && ReturnReg) { |
| 977 Context.insert<InstFakeDef>(ReturnReg); | 1138 Context.insert<InstFakeDef>(ReturnReg); |
| 978 } | 1139 } |
| (...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1646 Str << "\t.set\t" | 1807 Str << "\t.set\t" |
| 1647 << "nomips16\n"; | 1808 << "nomips16\n"; |
| 1648 } | 1809 } |
| 1649 | 1810 |
| 1650 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 1811 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; |
| 1651 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 1812 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; |
| 1652 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 1813 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; |
| 1653 | 1814 |
| 1654 } // end of namespace MIPS32 | 1815 } // end of namespace MIPS32 |
| 1655 } // end of namespace Ice | 1816 } // end of namespace Ice |
| OLD | NEW |