Chromium Code Reviews| Index: src/IceTargetLoweringMIPS32.cpp |
| diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp |
| index 121b8604f30f5521ad7a4ee993345b25ff98389a..b5f1f003070bc73b0662870d15a00dd7801aa2af 100644 |
| --- a/src/IceTargetLoweringMIPS32.cpp |
| +++ b/src/IceTargetLoweringMIPS32.cpp |
| @@ -64,6 +64,9 @@ 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; |
| + |
| const char *getRegClassName(RegClass C) { |
| auto ClassNum = static_cast<RegClassMIPS32>(C); |
| assert(ClassNum < RCMIPS32_NUM); |
| @@ -75,6 +78,24 @@ const char *getRegClassName(RegClass C) { |
| } |
| } |
| +// Stack alignment |
| +const uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16; |
|
Jim Stichnoth
2016/05/31 16:37:45
Can this be constexpr?
|
| + |
| +// Value is in bytes. Return Value adjusted to the next highest multiple of the |
| +// stack alignment. |
| +uint32_t applyStackAlignment(uint32_t Value) { |
| + return Utils::applyAlignment(Value, MIPS32_STACK_ALIGNMENT_BYTES); |
| +} |
| + |
| +// Value is in bytes. Return Value adjusted to the next highest multiple of the |
| +// stack alignment required for the given type. |
| +uint32_t applyStackAlignmentTy(uint32_t Value, Type Ty) { |
| + size_t typeAlignInBytes = typeWidthInBytes(Ty); |
| + if (isVectorType(Ty)) |
| + typeAlignInBytes = 8; |
| + return Utils::applyAlignment(Value, typeAlignInBytes); |
| +} |
| + |
| } // end of anonymous namespace |
| TargetMIPS32::TargetMIPS32(Cfg *Func) : TargetLowering(Func) {} |
| @@ -105,6 +126,13 @@ void TargetMIPS32::staticInit(GlobalContext *Ctx) { |
| assert(RegisterAliases[RegMIPS32::val][RegMIPS32::val]); |
| REGMIPS32_TABLE; |
| #undef X |
| + |
| + for(size_t i = 0; i<MIPS32_MAX_GPR_ARG ; i++) |
| + 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
|
| + |
| + for(size_t i = 0; i<MIPS32_MAX_GPR_ARG/2 ; i++) |
| + I64ArgInitializer[i] = RegNumT::fixme(RegMIPS32::Reg_A0A1 + i); |
| + |
| TypeToRegisterSet[IceType_void] = InvalidRegisters; |
| TypeToRegisterSet[IceType_i1] = IntegerRegisters; |
| TypeToRegisterSet[IceType_i8] = IntegerRegisters; |
| @@ -389,6 +417,53 @@ 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()) {} |
| + |
| +bool TargetMIPS32::CallingConv::argInGPR(Type Ty, RegNumT *Reg) { |
| + CfgVector<RegNumT> *Source; |
| + |
| + switch (Ty) { |
| + default: { |
| + assert(isScalarIntegerType(Ty)); |
| + Source = &GPRArgs; |
| + } break; |
| + case IceType_i64: { |
| + 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; |
| +} |
| + |
| +// GPR are not packed when passing parameters. Thus, a function foo(i32, i64, |
| +// i32) will have the first argument in r0, the second in r2-r3, 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()]) { |
| + GPRegsUsed |= RegisterAliases[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 |
| @@ -916,11 +991,82 @@ void TargetMIPS32::lowerBr(const InstBr *Instr) { |
| } |
| void TargetMIPS32::lowerCall(const InstCall *Instr) { |
| - // TODO(rkotler): assign arguments to registers and stack. Also reserve stack. |
| - if (Instr->getNumArgs()) { |
| - UnimplementedLoweringError(this, Instr); |
| - return; |
| + NeedsStackAlignment = true; |
| + |
| + // Assign arguments to registers and stack. Also reserve stack. |
| + TargetMIPS32::CallingConv CC; |
| + |
| + // Pair of Arg Operand -> GPR number assignments. |
| + llvm::SmallVector<std::pair<Operand *, RegNumT>, MIPS32_MAX_GPR_ARG> GPRArgs; |
| + |
| + // Pair of Arg Operand -> stack offset. |
| + llvm::SmallVector<std::pair<Operand *, int32_t>, 8> StackArgs; |
| + size_t ParameterAreaSizeBytes = 16; |
| + |
| + // Classify each argument operand according to the location where the |
| + // argument is passed. |
| + |
| + for (SizeT i = 0, NumArgs = Instr->getNumArgs(); i < NumArgs; ++i) { |
| + Operand *Arg = legalizeUndef(Instr->getArg(i)); |
| + const Type Ty = Arg->getType(); |
| + bool InReg = false; |
| + RegNumT Reg; |
| + if (isScalarIntegerType(Ty)) { |
| + InReg = CC.argInGPR(Ty, &Reg); |
| + } else { |
| + // TODO(mohit.bhakkad) : Handle arguments of type other than ScalarIntegerType |
|
Jim Stichnoth
2016/05/31 16:37:45
80-col, and pay special attention that "make forma
|
| + UnimplementedLoweringError(this, Instr); |
| + return; |
| + } |
| + |
| + if (!InReg) { |
| + ParameterAreaSizeBytes = |
| + applyStackAlignmentTy(ParameterAreaSizeBytes, Ty); |
| + StackArgs.push_back(std::make_pair(Arg, ParameterAreaSizeBytes)); |
| + ParameterAreaSizeBytes += typeWidthInBytesOnStack(Ty); |
| + continue; |
| + } |
| + |
| + if (Ty == IceType_i64) { |
| + Operand *Lo = loOperand(Arg); |
| + Operand *Hi = hiOperand(Arg); |
| + GPRArgs.push_back(std::make_pair( |
| + Lo, RegNumT::fixme(RegMIPS32::getI64PairFirstGPRNum(Reg)))); |
|
Jim Stichnoth
2016/05/31 16:37:45
Can these two fixme() calls be removed?
|
| + GPRArgs.push_back(std::make_pair( |
| + Hi, RegNumT::fixme(RegMIPS32::getI64PairSecondGPRNum(Reg)))); |
| + } else if (isScalarIntegerType(Ty)) { |
| + GPRArgs.push_back(std::make_pair(Arg, Reg)); |
| + } else { |
| + // TODO(mohit.bhakkad) : Handle arguments of type other than ScalarIntegerType |
| + UnimplementedLoweringError(this, Instr); |
| + return; |
| + } |
| + } |
| + |
| + // Adjust the parameter area so that the stack is aligned. It is assumed that |
| + // the stack is already aligned at the start of the calling sequence. |
| + ParameterAreaSizeBytes = applyStackAlignment(ParameterAreaSizeBytes); |
| + |
| + // Copy arguments that are passed on the stack to the appropriate stack |
| + // locations. |
| + Variable *SP = getPhysicalRegister(RegMIPS32::Reg_SP); |
| + for (auto &StackArg : StackArgs) { |
| + ConstantInteger32 *Loc = |
| + llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(StackArg.second)); |
| + Type Ty = StackArg.first->getType(); |
| + OperandMIPS32Mem *Addr; |
| + constexpr bool SignExt = false; |
| + if (OperandMIPS32Mem::canHoldOffset(Ty, SignExt, StackArg.second)) { |
| + Addr = OperandMIPS32Mem::create(Func, Ty, SP, Loc); |
| + } else {// ignoring this part for now |
| + Variable *NewBase = Func->makeVariable(SP->getType()); |
| + lowerArithmetic( |
| + InstArithmetic::create(Func, InstArithmetic::Add, NewBase, SP, Loc)); |
| + Addr = formMemoryOperand(NewBase, Ty); |
| + } |
| + lowerStore(InstStore::create(Func, StackArg.first, Addr)); |
| } |
| + |
| // Generate the call instruction. Assign its result to a temporary with high |
| // register allocation weight. |
| Variable *Dest = Instr->getDest(); |
| @@ -966,6 +1112,21 @@ void TargetMIPS32::lowerCall(const InstCall *Instr) { |
| if (!llvm::isa<ConstantRelocatable>(CallTarget)) { |
| CallTarget = legalize(CallTarget, Legal_Reg); |
| } |
| + |
| + // Copy arguments to be passed in registers to the appropriate registers. |
| + CfgVector<Variable *> RegArgs; |
| + for (auto &GPRArg : GPRArgs) { |
| + RegArgs.emplace_back(legalizeToReg(GPRArg.first, GPRArg.second)); |
| + } |
| + |
| + // Generate a FakeUse of register arguments so that they do not get dead code |
| + // eliminated as a result of the FakeKill of scratch registers after the call. |
| + // These fake-uses need to be placed here to avoid argument registers from |
| + // being used during the legalizeToReg() calls above. |
| + for (auto *RegArg : RegArgs) { |
| + Context.insert<InstFakeUse>(RegArg); |
| + } |
| + |
| Inst *NewCall = InstMIPS32Call::create(Func, ReturnReg, CallTarget); |
| Context.insert(NewCall); |
| if (ReturnRegHi) |