Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(567)

Unified Diff: src/IceTargetLoweringMIPS32.cpp

Issue 2021033002: [Subzero][MIPS32] Add argument handling in LowerCall (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Addressing review comments Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/IceTargetLoweringMIPS32.cpp
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 121b8604f30f5521ad7a4ee993345b25ff98389a..558d075a7cbfc1780780c96b2e898e885dc3697a 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
+constexpr uint32_t MIPS32_STACK_ALIGNMENT_BYTES = 16;
+
+// 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);
+
+ 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,84 @@ 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
+ 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, RegMIPS32::getI64PairFirstGPRNum(Reg)));
+ GPRArgs.push_back(
+ std::make_pair(Hi, 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 {
+ 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 +1114,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)

Powered by Google App Engine
This is Rietveld 408576698