| Index: src/IceTargetLoweringMIPS32.cpp
|
| diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
|
| index 70ddef531f88350f82bf5fc12e8d6b01cdca4ba9..79db2a1fa788d7ea7d0bd61f8221ad56e61dd942 100644
|
| --- a/src/IceTargetLoweringMIPS32.cpp
|
| +++ b/src/IceTargetLoweringMIPS32.cpp
|
| @@ -64,6 +64,14 @@ namespace {
|
| // The maximum number of arguments to pass in GPR registers.
|
| constexpr uint32_t MIPS32_MAX_GPR_ARG = 4;
|
|
|
| +std::array<RegNumT, MIPS32_MAX_GPR_ARG> GPRArgInitializer;
|
| +std::array<RegNumT, MIPS32_MAX_GPR_ARG / 2> I64ArgInitializer;
|
| +
|
| +constexpr uint32_t MIPS32_MAX_FP_ARG = 2;
|
| +
|
| +std::array<RegNumT, MIPS32_MAX_FP_ARG> FP32ArgInitializer;
|
| +std::array<RegNumT, MIPS32_MAX_FP_ARG> FP64ArgInitializer;
|
| +
|
| const char *getRegClassName(RegClass C) {
|
| auto ClassNum = static_cast<RegClassMIPS32>(C);
|
| assert(ClassNum < RCMIPS32_NUM);
|
| @@ -105,6 +113,20 @@ void TargetMIPS32::staticInit(GlobalContext *Ctx) {
|
| assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]);
|
| REGMIPS32_TABLE;
|
| #undef X
|
| +
|
| + // TODO(mohit.bhakkad): Change these inits once we provide argument related
|
| + // field in register tables
|
| + for (size_t i = 0; i < MIPS32_MAX_GPR_ARG; i++)
|
| + GPRArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0 + i);
|
| +
|
| + for (size_t i = 0; i < MIPS32_MAX_GPR_ARG / 2; i++)
|
| + I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i);
|
| +
|
| + for (size_t i = 0; i < MIPS32_MAX_FP_ARG; i++) {
|
| + FP32ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12 + i * 2);
|
| + FP64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_F12F13 + i);
|
| + }
|
| +
|
| TypeToRegisterSet[IceType_void] = InvalidRegisters;
|
| TypeToRegisterSet[IceType_i1] = IntegerRegisters;
|
| TypeToRegisterSet[IceType_i8] = IntegerRegisters;
|
| @@ -406,6 +428,135 @@ void TargetMIPS32::emitVariable(const Variable *Var) const {
|
| UnimplementedError(getFlags());
|
| }
|
|
|
| +TargetMIPS32::CallingConv::CallingConv()
|
| + : GPRegsUsed(RegMIPS32::Reg_NUM),
|
| + GPRArgs(GPRArgInitializer.rbegin(), GPRArgInitializer.rend()),
|
| + I64Args(I64ArgInitializer.rbegin(), I64ArgInitializer.rend()),
|
| + VFPRegsUsed(RegMIPS32::Reg_NUM),
|
| + FP32Args(FP32ArgInitializer.rbegin(), FP32ArgInitializer.rend()),
|
| + FP64Args(FP64ArgInitializer.rbegin(), FP64ArgInitializer.rend()) {}
|
| +
|
| +// In MIPS O32 abi FP argument registers can be used only if first argument is
|
| +// of type float/double. UseFPRegs flag is used to care of that. Also FP arg
|
| +// registers can be used only for first 2 arguments, so we require argument
|
| +// number to make register allocation decisions.
|
| +bool TargetMIPS32::CallingConv::argInReg(Type Ty, uint32_t ArgNo,
|
| + RegNumT *Reg) {
|
| + if (isScalarIntegerType(Ty))
|
| + return argInGPR(Ty, Reg);
|
| + if (isScalarFloatingType(Ty)) {
|
| + if (ArgNo == 0) {
|
| + UseFPRegs = true;
|
| + return argInVFP(Ty, Reg);
|
| + }
|
| + if (UseFPRegs && ArgNo == 1) {
|
| + UseFPRegs = false;
|
| + return argInVFP(Ty, Reg);
|
| + }
|
| + return argInGPR(Ty, Reg);
|
| + }
|
| + UnimplementedError(getFlags());
|
| + return false;
|
| +}
|
| +
|
| +bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) {
|
| + CfgVector<RegNumT> *Source;
|
| +
|
| + switch (Ty) {
|
| + default: {
|
| + UnimplementedError(getFlags());
|
| + return false;
|
| + } break;
|
| + case IceType_i32:
|
| + case IceType_f32: {
|
| + Source = &GPRArgs;
|
| + } break;
|
| + case IceType_i64:
|
| + case IceType_f64: {
|
| + Source = &I64Args;
|
| + } break;
|
| + }
|
| +
|
| + discardUnavailableGPRsAndTheirAliases(Source);
|
| +
|
| + if (Source->empty()) {
|
| + GPRegsUsed.set();
|
| + return false;
|
| + }
|
| +
|
| + *Reg = Source->back();
|
| + // Note that we don't Source->pop_back() here. This is intentional. Notice how
|
| + // we mark all of Reg's aliases as Used. So, for the next argument,
|
| + // Source->back() is marked as unavailable, and it is thus implicitly popped
|
| + // from the stack.
|
| + GPRegsUsed |= RegisterAliases[*Reg];
|
| + return true;
|
| +}
|
| +
|
| +inline void TargetMIPS32::CallingConv::discardNextGPRAndItsAliases(
|
| + CfgVector<RegNumT> *Regs) {
|
| + GPRegsUsed |= RegisterAliases[Regs->back()];
|
| + Regs->pop_back();
|
| +}
|
| +
|
| +// GPR are not packed when passing parameters. Thus, a function foo(i32, i64,
|
| +// i32) will have the first argument in a0, the second in a2-a3, and the third
|
| +// on the stack. To model this behavior, whenever we pop a register from Regs,
|
| +// we remove all of its aliases from the pool of available GPRs. This has the
|
| +// effect of computing the "closure" on the GPR registers.
|
| +void TargetMIPS32::CallingConv::discardUnavailableGPRsAndTheirAliases(
|
| + CfgVector<RegNumT> *Regs) {
|
| + while (!Regs->empty() && GPRegsUsed[Regs->back()]) {
|
| + discardNextGPRAndItsAliases(Regs);
|
| + }
|
| +}
|
| +
|
| +bool TargetMIPS32::CallingConv::argInVFP(Type Ty, RegNumT *Reg) {
|
| + CfgVector<RegNumT> *Source;
|
| +
|
| + switch (Ty) {
|
| + default: {
|
| + UnimplementedError(getFlags());
|
| + return false;
|
| + } break;
|
| + case IceType_f32: {
|
| + Source = &FP32Args;
|
| + } break;
|
| + case IceType_f64: {
|
| + Source = &FP64Args;
|
| + } break;
|
| + }
|
| +
|
| + discardUnavailableVFPRegsAndTheirAliases(Source);
|
| +
|
| + if (Source->empty()) {
|
| + VFPRegsUsed.set();
|
| + return false;
|
| + }
|
| +
|
| + *Reg = Source->back();
|
| + VFPRegsUsed |= RegisterAliases[*Reg];
|
| +
|
| + // In MIPS O32 abi if fun arguments are (f32, i32) then one can not use reg_a0
|
| + // for second argument even though it's free. f32 arg goes in reg_f12, i32 arg
|
| + // goes in reg_a1. Similarly if arguments are (f64, i32) second argument goes
|
| + // in reg_a3 and a0, a1 are not used.
|
| + Source = &GPRArgs;
|
| + // Discard one GPR reg for f32(4 bytes), two for f64(4 + 4 bytes)
|
| + discardNextGPRAndItsAliases(Source);
|
| + if (Ty == IceType_f64)
|
| + discardNextGPRAndItsAliases(Source);
|
| +
|
| + return true;
|
| +}
|
| +
|
| +void TargetMIPS32::CallingConv::discardUnavailableVFPRegsAndTheirAliases(
|
| + CfgVector<RegNumT> *Regs) {
|
| + while (!Regs->empty() && VFPRegsUsed[Regs->back()]) {
|
| + Regs->pop_back();
|
| + }
|
| +}
|
| +
|
| void TargetMIPS32::lowerArguments() {
|
| VarList &Args = Func->getArgs();
|
| // We are only handling integer registers for now. The Mips o32 ABI is
|
|
|