Commit f90118af by Mohit Bhakkad Committed by Jim Stichnoth

This patch provides calling convention class for MIPS with support of integer…

This patch provides calling convention class for MIPS with support of integer and floating point types R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2052793003 . Patch from Mohit Bhakkad <mohit.bhakkad@imgtec.com>.
parent f531931f
......@@ -111,38 +111,70 @@
#define REGMIPS32_FPR_TABLE \
/* val, encode, name, scratch, preserved, stackptr, frameptr, \
isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init */ \
X(Reg_F0, 0, "f0", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F0)) \
X(Reg_F1, 1, "f1", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F1)) \
X(Reg_F2, 2, "f2", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F2)) \
X(Reg_F3, 3, "f3", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F3)) \
X(Reg_F4, 4, "f4", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F4)) \
X(Reg_F5, 5, "f5", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F5)) \
X(Reg_F6, 6, "f6", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F6)) \
X(Reg_F7, 7, "f7", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F7)) \
X(Reg_F8, 8, "f8", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F8)) \
X(Reg_F9, 9, "f9", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F9)) \
X(Reg_F10, 10, "f10", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F10)) \
X(Reg_F11, 11, "f11", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F11)) \
X(Reg_F12, 12, "f12", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F12)) \
X(Reg_F13, 13, "f13", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F13)) \
X(Reg_F14, 14, "f14", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F14)) \
X(Reg_F15, 15, "f15", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F15)) \
X(Reg_F16, 16, "f16", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F16)) \
X(Reg_F17, 17, "f17", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F17)) \
X(Reg_F18, 18, "f18", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F18)) \
X(Reg_F19, 19, "f19", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F19)) \
X(Reg_F20, 20, "f20", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F20)) \
X(Reg_F21, 21, "f21", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F21)) \
X(Reg_F22, 22, "f22", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F22)) \
X(Reg_F23, 23, "f23", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F23)) \
X(Reg_F24, 24, "f24", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F24)) \
X(Reg_F25, 25, "f25", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F25)) \
X(Reg_F26, 26, "f26", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F26)) \
X(Reg_F27, 27, "f27", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F27)) \
X(Reg_F28, 28, "f28", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F28)) \
X(Reg_F29, 29, "f29", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F29)) \
X(Reg_F30, 30, "f30", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F30)) \
X(Reg_F31, 31, "f31", 1,0,0,0, 0,0,1,0,0, ALIASES1(Reg_F31))
X(Reg_F0, 0, "f0", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F0, Reg_F0F1)) \
X(Reg_F1, 1, "f1", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F1, Reg_F0F1)) \
X(Reg_F2, 2, "f2", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F2, Reg_F2F3)) \
X(Reg_F3, 3, "f3", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F3, Reg_F2F3)) \
X(Reg_F4, 4, "f4", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F4, Reg_F4F5)) \
X(Reg_F5, 5, "f5", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F5, Reg_F4F5)) \
X(Reg_F6, 6, "f6", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F6, Reg_F6F7)) \
X(Reg_F7, 7, "f7", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F7, Reg_F6F7)) \
X(Reg_F8, 8, "f8", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F8, Reg_F8F9)) \
X(Reg_F9, 9, "f9", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F9, Reg_F8F9)) \
X(Reg_F10, 10, "f10", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F10, Reg_F10F11)) \
X(Reg_F11, 11, "f11", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F11, Reg_F10F11)) \
X(Reg_F12, 12, "f12", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F12, Reg_F12F13)) \
X(Reg_F13, 13, "f13", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F13, Reg_F12F13)) \
X(Reg_F14, 14, "f14", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F14, Reg_F14F15)) \
X(Reg_F15, 15, "f15", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F15, Reg_F14F15)) \
X(Reg_F16, 16, "f16", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F16, Reg_F16F17)) \
X(Reg_F17, 17, "f17", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F17, Reg_F16F17)) \
X(Reg_F18, 18, "f18", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F18, Reg_F18F19)) \
X(Reg_F19, 19, "f19", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F19, Reg_F18F19)) \
X(Reg_F20, 20, "f20", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F20, Reg_F20F21)) \
X(Reg_F21, 21, "f21", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F21, Reg_F20F21)) \
X(Reg_F22, 22, "f22", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F22, Reg_F22F23)) \
X(Reg_F23, 23, "f23", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F23, Reg_F22F23)) \
X(Reg_F24, 24, "f24", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F24, Reg_F24F25)) \
X(Reg_F25, 25, "f25", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F25, Reg_F24F25)) \
X(Reg_F26, 26, "f26", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F26, Reg_F26F27)) \
X(Reg_F27, 27, "f27", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F27, Reg_F26F27)) \
X(Reg_F28, 28, "f28", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F28, Reg_F28F29)) \
X(Reg_F29, 29, "f29", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F29, Reg_F28F29)) \
X(Reg_F30, 30, "f30", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F30, Reg_F30F31)) \
X(Reg_F31, 31, "f31", 1,0,0,0, 0,0,1,0,0, \
ALIASES2(Reg_F31, Reg_F30F31)) \
//#define X(val, encode, name, scratch, preserved, stackptr, frameptr,
// isInt, isI64Pair, isFP32, isFP64, isVec128, alias_init)
......
......@@ -89,6 +89,24 @@ static inline bool isFPRReg(RegNumT RegNum) {
const char *getRegName(RegNumT RegNum);
static inline RegNumT getI64PairFirstGPRNum(RegNumT RegNum) {
// For now it works only for argument register pairs
// TODO(mohit.bhakkad): Change this to support all the register pairs once we
// have table-driven approach ready
assert(RegNum == Reg_A0A1 || RegNum == Reg_A2A3);
return (RegNum == RegMIPS32::Reg_A0A1) ? RegMIPS32::Reg_A0
: RegMIPS32::Reg_A2;
}
static inline RegNumT getI64PairSecondGPRNum(RegNumT RegNum) {
// For now it works only for argument register pairs
// TODO(mohit.bhakkad): Change this to support all the register pairs once we
// have table-driven approach ready
assert(RegNum == Reg_A0A1 || RegNum == Reg_A2A3);
return (RegNum == RegMIPS32::Reg_A0A1) ? RegMIPS32::Reg_A1
: RegMIPS32::Reg_A3;
}
} // end of namespace RegMIPS32
// Extend enum RegClass with MIPS32-specific register classes (if any).
......
......@@ -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
......
......@@ -459,6 +459,43 @@ public:
Operand *legalizeUndef(Operand *From, RegNumT RegNum = RegNumT());
/// Helper class that understands the Calling Convention and register
/// assignments as per MIPS O32 abi.
class CallingConv {
CallingConv(const CallingConv &) = delete;
CallingConv &operator=(const CallingConv &) = delete;
public:
CallingConv();
~CallingConv() = default;
/// argInReg returns true if there is a Register available for the requested
/// type, and false otherwise. If it returns true, Reg is set to the
/// appropriate register number. Note that, when Ty == IceType_i64, Reg will
/// be an I64 register pair.
bool argInReg(Type Ty, uint32_t ArgNo, RegNumT *Reg);
private:
// argInGPR is used to find if any GPR register is available for argument of
// type Ty
bool argInGPR(Type Ty, RegNumT *Reg);
/// argInVFP is to floating-point/vector types what argInGPR is for integer
/// types.
bool argInVFP(Type Ty, RegNumT *Reg);
inline void discardNextGPRAndItsAliases(CfgVector<RegNumT> *Regs);
void discardUnavailableGPRsAndTheirAliases(CfgVector<RegNumT> *Regs);
SmallBitVector GPRegsUsed;
CfgVector<RegNumT> GPRArgs;
CfgVector<RegNumT> I64Args;
void discardUnavailableVFPRegsAndTheirAliases(CfgVector<RegNumT> *Regs);
SmallBitVector VFPRegsUsed;
CfgVector<RegNumT> FP32Args;
CfgVector<RegNumT> FP64Args;
// UseFPRegs is a flag indicating if FP registers can be used
bool UseFPRegs = false;
};
protected:
explicit TargetMIPS32(Cfg *Func);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment