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 constexpr uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16; |
| 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); |
| 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 |
| 1018 // ScalarIntegerType |
| 1019 UnimplementedLoweringError(this, Instr); |
| 1020 return; |
| 1021 } |
| 1022 |
| 1023 if (!InReg) { |
| 1024 ParameterAreaSizeBytes = |
| 1025 applyStackAlignmentTy(ParameterAreaSizeBytes, Ty); |
| 1026 StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes)); |
| 1027 ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty); |
| 1028 continue; |
| 1029 } |
| 1030 |
| 1031 if (Ty == IceType_i64) { |
| 1032 Operand *Lo = loOperand(Arg); |
| 1033 Operand *Hi = hiOperand(Arg); |
| 1034 GPRArgs.push_back( |
| 1035 std::make_pair(Lo, RegMIPS32::getI64PairFirstGPRNum(Reg))); |
| 1036 GPRArgs.push_back( |
| 1037 std::make_pair(Hi, RegMIPS32::getI64PairSecondGPRNum(Reg))); |
| 1038 } else if (isScalarIntegerType(Ty)) { |
| 1039 GPRArgs.push_back(std::make_pair(Arg, Reg)); |
| 1040 } else { |
| 1041 // TODO(mohit.bhakkad) : Handle arguments of type other than |
| 1042 // ScalarIntegerType |
| 1043 UnimplementedLoweringError(this, Instr); |
| 1044 return; |
| 1045 } |
923 } | 1046 } |
| 1047 |
| 1048 // Adjust the parameter area so that the stack is aligned. It is assumed that |
| 1049 // the stack is already aligned at the start of the calling sequence. |
| 1050 ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes); |
| 1051 |
| 1052 // Copy arguments that are passed on the stack to the appropriate stack |
| 1053 // locations. |
| 1054 Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); |
| 1055 for (auto &StackArg : StackArgs) { |
| 1056 ConstantInteger32 *Loc = |
| 1057 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second)); |
| 1058 Type Ty = StackArg.first->getType(); |
| 1059 OperandMIPS32Mem *Addr; |
| 1060 constexpr bool SignExt = false; |
| 1061 if (OperandMIPS32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) { |
| 1062 Addr = OperandMIPS32Mem::create(Func, Ty, SP, Loc); |
| 1063 } else { |
| 1064 Variable *NewBase = Func->makeVariable(SP->getType()); |
| 1065 lowerArithmetic( |
| 1066 InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc)); |
| 1067 Addr = formMemoryOperand(NewBase, Ty); |
| 1068 } |
| 1069 lowerStore(InstStore::create(Func, StackArg.first, Addr)); |
| 1070 } |
| 1071 |
924 // Generate the call instruction. Assign its result to a temporary with high | 1072 // Generate the call instruction. Assign its result to a temporary with high |
925 // register allocation weight. | 1073 // register allocation weight. |
926 Variable *Dest = Instr->getDest(); | 1074 Variable *Dest = Instr->getDest(); |
927 // ReturnReg doubles as ReturnRegLo as necessary. | 1075 // ReturnReg doubles as ReturnRegLo as necessary. |
928 Variable *ReturnReg = nullptr; | 1076 Variable *ReturnReg = nullptr; |
929 Variable *ReturnRegHi = nullptr; | 1077 Variable *ReturnRegHi = nullptr; |
930 if (Dest) { | 1078 if (Dest) { |
931 switch (Dest->getType()) { | 1079 switch (Dest->getType()) { |
932 case IceType_NUM: | 1080 case IceType_NUM: |
933 llvm_unreachable("Invalid Call dest type"); | 1081 llvm_unreachable("Invalid Call dest type"); |
(...skipping 25 matching lines...) Expand all Loading... |
959 return; | 1107 return; |
960 } | 1108 } |
961 } | 1109 } |
962 Operand *CallTarget = Instr->getCallTarget(); | 1110 Operand *CallTarget = Instr->getCallTarget(); |
963 // Allow ConstantRelocatable to be left alone as a direct call, | 1111 // Allow ConstantRelocatable to be left alone as a direct call, |
964 // but force other constants like ConstantInteger32 to be in | 1112 // but force other constants like ConstantInteger32 to be in |
965 // a register and make it an indirect call. | 1113 // a register and make it an indirect call. |
966 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { | 1114 if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
967 CallTarget = legalize(CallTarget, Legal_Reg); | 1115 CallTarget = legalize(CallTarget, Legal_Reg); |
968 } | 1116 } |
| 1117 |
| 1118 // Copy arguments to be passed in registers to the appropriate registers. |
| 1119 CfgVector<Variable *> RegArgs; |
| 1120 for (auto &GPRArg : GPRArgs) { |
| 1121 RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second)); |
| 1122 } |
| 1123 |
| 1124 // Generate a FakeUse of register arguments so that they do not get dead code |
| 1125 // eliminated as a result of the FakeKill of scratch registers after the call. |
| 1126 // These fake-uses need to be placed here to avoid argument registers from |
| 1127 // being used during the legalizeToReg() calls above. |
| 1128 for (auto *RegArg : RegArgs) { |
| 1129 Context.insert<InstFakeUse>(RegArg); |
| 1130 } |
| 1131 |
969 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); | 1132 Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); |
970 Context.insert(NewCall); | 1133 Context.insert(NewCall); |
971 if (ReturnRegHi) | 1134 if (ReturnRegHi) |
972 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); | 1135 Context.insert(InstFakeDef::create(Func, ReturnRegHi)); |
973 // Insert a register-kill pseudo instruction. | 1136 // Insert a register-kill pseudo instruction. |
974 Context.insert(InstFakeKill::create(Func, NewCall)); | 1137 Context.insert(InstFakeKill::create(Func, NewCall)); |
975 // Generate a FakeUse to keep the call live if necessary. | 1138 // Generate a FakeUse to keep the call live if necessary. |
976 if (Instr->hasSideEffects() && ReturnReg) { | 1139 if (Instr->hasSideEffects() && ReturnReg) { |
977 Context.insert<InstFakeDef>(ReturnReg); | 1140 Context.insert<InstFakeDef>(ReturnReg); |
978 } | 1141 } |
(...skipping 667 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1646 Str << "\t.set\t" | 1809 Str << "\t.set\t" |
1647 << "nomips16\n"; | 1810 << "nomips16\n"; |
1648 } | 1811 } |
1649 | 1812 |
1650 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; | 1813 SmallBitVector TargetMIPS32::TypeToRegisterSet[RCMIPS32_NUM]; |
1651 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; | 1814 SmallBitVector TargetMIPS32::TypeToRegisterSetUnfiltered[RCMIPS32_NUM]; |
1652 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; | 1815 SmallBitVector TargetMIPS32::RegisterAliases[RegMIPS32::Reg_NUM]; |
1653 | 1816 |
1654 } // end of namespace MIPS32 | 1817 } // end of namespace MIPS32 |
1655 } // end of namespace Ice | 1818 } // end of namespace Ice |
OLD | NEW |